blob: 15ff61b5783f47137f08a6225afc358bf9073795 [file] [edit]
/*
* Copyright (c) 2020, 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 "rest/json.hpp"
#include "types.hpp"
#include <map>
#include <set>
#include <sstream>
#include "common/code_utils.hpp"
#include "common/types.hpp"
#include "openthread/mesh_diag.h"
#include "openthread/platform/radio.h"
#include "utils/string_utils.hpp"
extern "C" {
#include <cJSON.h>
}
#ifndef BITS_PER_BYTE
#define BITS_PER_BYTE 8
#endif
namespace otbr {
namespace rest {
namespace Json {
/**
* @brief Concat str1, '.', and str2.
*
* @param str1 A string.
* @param str2 Another string.
* @return std::string str1.str2
*/
std::string concat(const char *str1, const char *str2)
{
return (std::string(str1) + "." + std::string(str2));
}
/**
* @brief Check if aKey is part of aSet.
*
* @param aSet A set of strings representing keys.
* @param aKey A key
* @return true If aSet is empty (default, for return any key),
* aKey is in aSet, or both,
* aKey = 'atoplevelKey.asecondlevelKey' AND 'atoplevelKey.' are in aSet.
* @return false Otherwise.
*
* the logic in this implementation relates to parsing the query to the set aSet
* as implemented by BasicCollectionItem::parseQueryFieldValues
*/
static bool hasKey(std::set<std::string> aSet, std::string aKey)
{
bool ret = false;
std::string topKey;
std::size_t pos;
if (aSet.empty())
{
// defaults to has any key
ret = true;
ExitNow();
}
// for a second level key in aKey
// check if the top level key is present as well
pos = aKey.find(".");
if (pos != std::string::npos)
{
topKey = aKey.substr(0, pos + 1);
}
if (!topKey.empty() && aSet.find(aKey) != aSet.end() && aSet.find(topKey) != aSet.end())
{
ret = true;
ExitNow();
}
// simple key 'aKey' or
// comes here when 'atoplevelKey.asecondlevelKey' is not in aSet
pos = aKey.find(".");
if (pos != std::string::npos)
{
// ignore asecondlevelKey and look for 'atoplevelKey'
aKey = aKey.substr(0, pos);
}
if (aSet.find(aKey) != aSet.end())
{
ret = true;
}
exit:
return ret;
}
/**
* @brief Check if aKey or aKey. is in aSet.
*
* @param aSet A set of strings representing keys.
* @param aKey A potential toplevel key.
* @return true if 'aKey' or 'aKey.' is in aSet
* @return false Otherwise.
*/
static bool hasToplevelKey(std::set<std::string> aSet, std::string aKey)
{
return (hasKey(aSet, aKey) || (hasKey(aSet, aKey + ".")));
}
static cJSON *MeshChildTable2Json(const std::vector<otMeshDiagChildEntry> &aChildren);
static cJSON *MeshRouterNeighbors2Json(const std::vector<otMeshDiagRouterNeighborEntry> &aNeighbors);
static cJSON *MeshChildIp62Json(const DeviceIp6Addrs &aChildIp6Addrs);
static cJSON *MeshChildrenIp62Json(const std::vector<DeviceIp6Addrs> &aChildrenIp6Addrs);
// static cJSON *JsonApiMetaDiagCollection2cJSON(uint16_t router_count, uint16_t children_count, uint16_t no_response);
static cJSON *Bytes2HexJson(const uint8_t *aBytes, uint8_t aLength)
{
std::string hex = otbr::Utils::Bytes2Hex(aBytes, aLength);
return cJSON_CreateString(StringUtils::ToLowercase(hex).c_str());
}
static cJSON *Number2HexJson(const uint16_t aNumber)
{
char hex[6 + 1] = {'\0'};
snprintf(hex, sizeof(hex), "0x%04X", aNumber);
return cJSON_CreateString(StringUtils::ToLowercase(hex).c_str());
}
std::string String2JsonString(const std::string &aString)
{
std::string ret;
cJSON *json = nullptr;
char *jsonOut = nullptr;
VerifyOrExit(aString.size() > 0);
json = cJSON_CreateString(aString.c_str());
jsonOut = cJSON_Print(json);
ret = jsonOut;
if (jsonOut != nullptr)
{
cJSON_free(jsonOut);
jsonOut = nullptr;
}
cJSON_Delete(json);
exit:
return ret;
}
bool JsonString2String(const std::string &aJsonString, std::string &aString)
{
cJSON *jsonString;
bool ret = true;
VerifyOrExit((jsonString = cJSON_Parse(aJsonString.c_str())) != nullptr, ret = false);
VerifyOrExit(cJSON_IsString(jsonString), ret = false);
aString = std::string(jsonString->valuestring);
exit:
cJSON_Delete(jsonString);
return ret;
}
std::string Json2String(const cJSON *aJson)
{
std::string ret;
char *jsonOut = nullptr;
VerifyOrExit(aJson != nullptr);
jsonOut = cJSON_Print(aJson);
ret = jsonOut;
if (jsonOut != nullptr)
{
cJSON_free(jsonOut);
jsonOut = nullptr;
}
exit:
return ret;
}
static cJSON *CString2Json(const char *aString)
{
return cJSON_CreateString(aString);
}
static cJSON *Mode2Json(const otLinkModeConfig &aMode)
{
cJSON *mode = cJSON_CreateObject();
cJSON_AddItemToObject(mode, KEY_RXONWHENIDLE, cJSON_CreateBool(aMode.mRxOnWhenIdle));
cJSON_AddItemToObject(mode, KEY_ISFTD, cJSON_CreateBool(aMode.mDeviceType));
cJSON_AddItemToObject(mode, KEY_FULLNETWORKDATA, cJSON_CreateBool(aMode.mNetworkData));
return mode;
}
static cJSON *IpAddr2Json(const otIp6Address &aAddress)
{
Ip6Address addr(aAddress.mFields.m8);
return cJSON_CreateString(addr.ToString().c_str());
}
static cJSON *IpPrefix2Json(const otIp6NetworkPrefix &aAddress)
{
std::stringstream ss;
otIp6Address address = {};
address.mFields.mComponents.mNetworkPrefix = aAddress;
Ip6Address addr(address.mFields.m8);
ss << addr.ToString() << "/" << OT_IP6_PREFIX_BITSIZE;
return cJSON_CreateString(ss.str().c_str());
}
otbrError Json2IpPrefix(const cJSON *aJson, otIp6NetworkPrefix &aIpPrefix)
{
otbrError error = OTBR_ERROR_NONE;
std::istringstream ipPrefixStr(std::string(aJson->valuestring));
std::string tmp;
Ip6Address addr;
VerifyOrExit(std::getline(ipPrefixStr, tmp, '/'), error = OTBR_ERROR_INVALID_ARGS);
VerifyOrExit((error = addr.FromString(tmp.c_str(), addr)) == OTBR_ERROR_NONE);
memcpy(aIpPrefix.m8, addr.m8, OT_IP6_PREFIX_SIZE);
exit:
return error;
}
static cJSON *Timestamp2Json(const otTimestamp &aTimestamp)
{
cJSON *timestamp = cJSON_CreateObject();
cJSON_AddItemToObject(timestamp, KEY_SECONDS, cJSON_CreateNumber(aTimestamp.mSeconds));
cJSON_AddItemToObject(timestamp, KEY_TICKS, cJSON_CreateNumber(aTimestamp.mTicks));
cJSON_AddItemToObject(timestamp, KEY_AUTHORITATIVE, cJSON_CreateBool(aTimestamp.mAuthoritative));
return timestamp;
}
bool Json2Timestamp(const cJSON *jsonTimestamp, otTimestamp &aTimestamp)
{
cJSON *value;
value = cJSON_GetObjectItemCaseSensitive(jsonTimestamp, KEY_SECONDS);
if (cJSON_IsNumber(value))
{
aTimestamp.mSeconds = static_cast<uint64_t>(value->valuedouble);
}
else if (value != nullptr)
{
return false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonTimestamp, KEY_TICKS);
if (cJSON_IsNumber(value))
{
aTimestamp.mTicks = static_cast<uint16_t>(value->valueint);
}
else if (value != nullptr)
{
return false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonTimestamp, KEY_AUTHORITATIVE);
aTimestamp.mAuthoritative = cJSON_IsTrue(value);
return true;
}
static cJSON *SecurityPolicy2Json(const otSecurityPolicy &aSecurityPolicy)
{
cJSON *securityPolicy = cJSON_CreateObject();
cJSON_AddItemToObject(securityPolicy, KEY_ROTATIONTIME, cJSON_CreateNumber(aSecurityPolicy.mRotationTime));
cJSON_AddItemToObject(securityPolicy, KEY_OBTAINNETWORKKEY,
cJSON_CreateBool(aSecurityPolicy.mObtainNetworkKeyEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_NATIVECOMMISSIONING,
cJSON_CreateBool(aSecurityPolicy.mNativeCommissioningEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_ROUTERS, cJSON_CreateBool(aSecurityPolicy.mRoutersEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_EXTERNALCOMMISSIONING,
cJSON_CreateBool(aSecurityPolicy.mExternalCommissioningEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_COMMERCIALCOMMISSIONING,
cJSON_CreateBool(aSecurityPolicy.mCommercialCommissioningEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_AUTONOMOUSENROLLMENT,
cJSON_CreateBool(aSecurityPolicy.mAutonomousEnrollmentEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_NETWORKKEYPROVISIONING,
cJSON_CreateBool(aSecurityPolicy.mNetworkKeyProvisioningEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_TOBLELINK, cJSON_CreateBool(aSecurityPolicy.mTobleLinkEnabled));
cJSON_AddItemToObject(securityPolicy, KEY_NONCCMROUTERS, cJSON_CreateBool(aSecurityPolicy.mNonCcmRoutersEnabled));
return securityPolicy;
}
bool Json2SecurityPolicy(const cJSON *jsonSecurityPolicy, otSecurityPolicy &aSecurityPolicy)
{
cJSON *value;
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_ROTATIONTIME);
if (cJSON_IsNumber(value))
{
aSecurityPolicy.mRotationTime = static_cast<uint16_t>(value->valueint);
}
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_OBTAINNETWORKKEY);
aSecurityPolicy.mObtainNetworkKeyEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_NATIVECOMMISSIONING);
aSecurityPolicy.mNativeCommissioningEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_ROUTERS);
aSecurityPolicy.mRoutersEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_EXTERNALCOMMISSIONING);
aSecurityPolicy.mExternalCommissioningEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_COMMERCIALCOMMISSIONING);
aSecurityPolicy.mCommercialCommissioningEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_AUTONOMOUSENROLLMENT);
aSecurityPolicy.mAutonomousEnrollmentEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_NETWORKKEYPROVISIONING);
aSecurityPolicy.mNetworkKeyProvisioningEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_TOBLELINK);
aSecurityPolicy.mTobleLinkEnabled = cJSON_IsTrue(value);
value = cJSON_GetObjectItemCaseSensitive(jsonSecurityPolicy, KEY_NONCCMROUTERS);
aSecurityPolicy.mNonCcmRoutersEnabled = cJSON_IsTrue(value);
return true;
}
static cJSON *ChildTableEntry2Json(const otNetworkDiagChildEntry &aChildEntry)
{
cJSON *childEntry = cJSON_CreateObject();
cJSON_AddItemToObject(childEntry, KEY_CHILDID, cJSON_CreateNumber(aChildEntry.mChildId));
cJSON_AddItemToObject(childEntry, KEY_TIMEOUT, cJSON_CreateNumber(aChildEntry.mTimeout));
cJSON_AddItemToObject(childEntry, KEY_LINKQUALITY, cJSON_CreateNumber(aChildEntry.mLinkQuality));
cJSON *mode = Mode2Json(aChildEntry.mMode);
cJSON_AddItemToObject(childEntry, KEY_MODE, mode);
return childEntry;
}
static cJSON *MacCounters2Json(const otNetworkDiagMacCounters &aMacCounters)
{
cJSON *macCounters = cJSON_CreateObject();
cJSON_AddItemToObject(macCounters, KEY_IFINUNKNOWNPROTOS, cJSON_CreateNumber(aMacCounters.mIfInUnknownProtos));
cJSON_AddItemToObject(macCounters, KEY_IFINERRORS, cJSON_CreateNumber(aMacCounters.mIfInErrors));
cJSON_AddItemToObject(macCounters, KEY_IFOUTERRORS, cJSON_CreateNumber(aMacCounters.mIfOutErrors));
cJSON_AddItemToObject(macCounters, KEY_IFINUCASTPKTS, cJSON_CreateNumber(aMacCounters.mIfInUcastPkts));
cJSON_AddItemToObject(macCounters, KEY_IFINBROADCASTPKTS, cJSON_CreateNumber(aMacCounters.mIfInBroadcastPkts));
cJSON_AddItemToObject(macCounters, KEY_IFINDISCARDS, cJSON_CreateNumber(aMacCounters.mIfInDiscards));
cJSON_AddItemToObject(macCounters, KEY_IFOUTUCASTPKTS, cJSON_CreateNumber(aMacCounters.mIfOutUcastPkts));
cJSON_AddItemToObject(macCounters, KEY_IFOUTBROADCASTPKTS, cJSON_CreateNumber(aMacCounters.mIfOutBroadcastPkts));
cJSON_AddItemToObject(macCounters, KEY_IFOUTDISCARDS, cJSON_CreateNumber(aMacCounters.mIfOutDiscards));
return macCounters;
}
static cJSON *MleCounters2Json(const otNetworkDiagMleCounters &aMleCounters)
{
cJSON *mleCounters = cJSON_CreateObject();
cJSON_AddItemToObject(mleCounters, KEY_RADIODISABLEDCOUNT, cJSON_CreateNumber(aMleCounters.mDisabledRole));
cJSON_AddItemToObject(mleCounters, KEY_DETACHEDROLECOUNT, cJSON_CreateNumber(aMleCounters.mDetachedRole));
cJSON_AddItemToObject(mleCounters, KEY_CHILDROLECOUNT, cJSON_CreateNumber(aMleCounters.mChildRole));
cJSON_AddItemToObject(mleCounters, KEY_ROUTERROLECOUNT, cJSON_CreateNumber(aMleCounters.mRouterRole));
cJSON_AddItemToObject(mleCounters, KEY_LEADERROLECOUNT, cJSON_CreateNumber(aMleCounters.mLeaderRole));
cJSON_AddItemToObject(mleCounters, KEY_ATTACHATTEMPTSCOUNT, cJSON_CreateNumber(aMleCounters.mAttachAttempts));
cJSON_AddItemToObject(mleCounters, KEY_PARTIDCHANGESCOUNT, cJSON_CreateNumber(aMleCounters.mPartitionIdChanges));
cJSON_AddItemToObject(mleCounters, KEY_BETTERPARTIDATTEMPTSCOUNT,
cJSON_CreateNumber(aMleCounters.mBetterPartitionAttachAttempts));
cJSON_AddItemToObject(mleCounters, KEY_NEWPARENTCOUNT, cJSON_CreateNumber(aMleCounters.mParentChanges));
cJSON_AddItemToObject(mleCounters, KEY_TOTALTRACKINGTIME, cJSON_CreateNumber(aMleCounters.mTrackedTime));
cJSON_AddItemToObject(mleCounters, KEY_RADIODISABLEDTIME, cJSON_CreateNumber(aMleCounters.mDisabledTime));
cJSON_AddItemToObject(mleCounters, KEY_DETACHEDROLETIME, cJSON_CreateNumber(aMleCounters.mDetachedTime));
cJSON_AddItemToObject(mleCounters, KEY_CHILDROLETIME, cJSON_CreateNumber(aMleCounters.mChildTime));
cJSON_AddItemToObject(mleCounters, KEY_ROUTERROLETIME, cJSON_CreateNumber(aMleCounters.mRouterTime));
cJSON_AddItemToObject(mleCounters, KEY_LEADERROLETIME, cJSON_CreateNumber(aMleCounters.mLeaderTime));
return mleCounters;
}
static cJSON *Connectivity2Json(const otNetworkDiagConnectivity &aConnectivity)
{
cJSON *connectivity = cJSON_CreateObject();
cJSON_AddItemToObject(connectivity, KEY_PARENTPRIORITY, cJSON_CreateNumber(aConnectivity.mParentPriority));
cJSON_AddItemToObject(connectivity, KEY_LINKQUALITY3, cJSON_CreateNumber(aConnectivity.mLinkQuality3));
cJSON_AddItemToObject(connectivity, KEY_LINKQUALITY2, cJSON_CreateNumber(aConnectivity.mLinkQuality2));
cJSON_AddItemToObject(connectivity, KEY_LINKQUALITY1, cJSON_CreateNumber(aConnectivity.mLinkQuality1));
cJSON_AddItemToObject(connectivity, KEY_LEADERCOST, cJSON_CreateNumber(aConnectivity.mLeaderCost));
cJSON_AddItemToObject(connectivity, KEY_IDSEQUENCE, cJSON_CreateNumber(aConnectivity.mIdSequence));
cJSON_AddItemToObject(connectivity, KEY_ACTIVEROUTERS, cJSON_CreateNumber(aConnectivity.mActiveRouters));
cJSON_AddItemToObject(connectivity, KEY_SEDBUFFERSIZE, cJSON_CreateNumber(aConnectivity.mSedBufferSize));
cJSON_AddItemToObject(connectivity, KEY_SEDDATAGRAMCOUNT, cJSON_CreateNumber(aConnectivity.mSedDatagramCount));
return connectivity;
}
static cJSON *RouteData2Json(const otNetworkDiagRouteData &aRouteData)
{
cJSON *routeData = cJSON_CreateObject();
cJSON_AddItemToObject(routeData, KEY_ROUTEID, cJSON_CreateNumber(aRouteData.mRouterId));
cJSON_AddItemToObject(routeData, KEY_LINKQUALITYOUT, cJSON_CreateNumber(aRouteData.mLinkQualityOut));
cJSON_AddItemToObject(routeData, KEY_LINKQUALITYIN, cJSON_CreateNumber(aRouteData.mLinkQualityIn));
cJSON_AddItemToObject(routeData, KEY_ROUTECOST, cJSON_CreateNumber(aRouteData.mRouteCost));
return routeData;
}
static cJSON *Route2Json(const otNetworkDiagRoute &aRoute)
{
cJSON *route = cJSON_CreateObject();
cJSON_AddItemToObject(route, KEY_IDSEQUENCE, cJSON_CreateNumber(aRoute.mIdSequence));
cJSON *RouteData = cJSON_CreateArray();
for (uint16_t i = 0; i < aRoute.mRouteCount; ++i)
{
cJSON *RouteDatavalue = RouteData2Json(aRoute.mRouteData[i]);
cJSON_AddItemToArray(RouteData, RouteDatavalue);
}
cJSON_AddItemToObject(route, KEY_ROUTEDATA, RouteData);
return route;
}
static cJSON *LeaderData2Json(const otLeaderData &aLeaderData)
{
cJSON *leaderData = cJSON_CreateObject();
cJSON_AddItemToObject(leaderData, KEY_PARTITIONID, cJSON_CreateNumber(aLeaderData.mPartitionId));
cJSON_AddItemToObject(leaderData, KEY_WEIGHTING, cJSON_CreateNumber(aLeaderData.mWeighting));
cJSON_AddItemToObject(leaderData, KEY_DATAVERSION, cJSON_CreateNumber(aLeaderData.mDataVersion));
cJSON_AddItemToObject(leaderData, KEY_STABLEDATAVERSION, cJSON_CreateNumber(aLeaderData.mStableDataVersion));
cJSON_AddItemToObject(leaderData, KEY_LEADERROUTERID, cJSON_CreateNumber(aLeaderData.mLeaderRouterId));
return leaderData;
}
std::string IpAddr2JsonString(const otIp6Address &aAddress)
{
std::string ret;
cJSON *ipAddr = IpAddr2Json(aAddress);
ret = Json2String(ipAddr);
cJSON_Delete(ipAddr);
return ret;
}
cJSON *Node2Json(const NodeInfo &aNode, std::set<std::string> aFieldset)
{
cJSON *node = cJSON_CreateObject();
if (hasKey(aFieldset, KEY_BORDERAGENTID))
{
cJSON_AddItemToObject(node, KEY_BORDERAGENTID, Bytes2HexJson(aNode.mBaId.mId, sizeof(aNode.mBaId)));
}
if (hasKey(aFieldset, KEY_BORDERAGENTSTATE))
{
cJSON_AddItemToObject(node, KEY_BORDERAGENTSTATE, cJSON_CreateString(aNode.mBaState.c_str()));
}
if (hasKey(aFieldset, KEY_STATE))
{
cJSON_AddItemToObject(node, KEY_STATE, cJSON_CreateString(aNode.mRole.c_str()));
}
if (hasKey(aFieldset, KEY_ROUTERCOUNT))
{
cJSON_AddItemToObject(node, KEY_ROUTERCOUNT, cJSON_CreateNumber(aNode.mNumOfRouter));
}
if (hasKey(aFieldset, KEY_RLOC16_IPV6ADDRESS))
{
cJSON_AddItemToObject(node, KEY_RLOC16_IPV6ADDRESS, IpAddr2Json(aNode.mRlocAddress));
}
if (hasKey(aFieldset, KEY_EXTADDRESS))
{
cJSON_AddItemToObject(node, KEY_EXTADDRESS, Bytes2HexJson(aNode.mExtAddress, OT_EXT_ADDRESS_SIZE));
}
if (hasKey(aFieldset, KEY_NETWORKNAME))
{
cJSON_AddItemToObject(node, KEY_NETWORKNAME, cJSON_CreateString(aNode.mNetworkName.c_str()));
}
if (hasKey(aFieldset, KEY_RLOC16))
{
cJSON_AddItemToObject(node, KEY_RLOC16, Number2HexJson(aNode.mRloc16));
}
if (hasKey(aFieldset, KEY_ROUTERID))
{
if ((aNode.mRloc16 & CHILD_MASK) == 0)
{
cJSON_AddItemToObject(node, KEY_ROUTERID, cJSON_CreateNumber(aNode.mRloc16 >> 10));
}
}
if (hasKey(aFieldset, KEY_LEADERDATA))
{
cJSON_AddItemToObject(node, KEY_LEADERDATA, LeaderData2Json(aNode.mLeaderData));
}
if (hasKey(aFieldset, KEY_EXTPANID))
{
cJSON_AddItemToObject(node, KEY_EXTPANID, Bytes2HexJson(aNode.mExtPanId, OT_EXT_PAN_ID_SIZE));
}
return node;
}
std::string Node2JsonString(const NodeInfo &aNode)
{
std::string ret;
std::set<std::string> fieldset;
cJSON *node = Node2Json(aNode, fieldset);
ret = Json2String(node);
cJSON_Delete(node);
return ret;
}
std::string SparseNode2JsonString(const NodeInfo &aNode, std::set<std::string> aFieldset)
{
std::string ret;
cJSON *node = Node2Json(aNode, aFieldset);
ret = Json2String(node);
cJSON_Delete(node);
return ret;
}
cJSON *brCounter2Json(const otBorderRoutingCounters *aBrCounters)
{
cJSON *ret = cJSON_CreateObject();
cJSON_AddNumberToObject(ret, KEY_IFINUCASTPKTS, aBrCounters->mInboundUnicast.mPackets);
cJSON_AddNumberToObject(ret, KEY_IFINBROADCASTPKTS, aBrCounters->mInboundMulticast.mPackets);
cJSON_AddNumberToObject(ret, KEY_IFOUTUCASTPKTS, aBrCounters->mOutboundUnicast.mPackets);
cJSON_AddNumberToObject(ret, KEY_IFOUTBROADCASTPKTS, aBrCounters->mOutboundMulticast.mPackets);
cJSON_AddNumberToObject(ret, KEY_RARX, aBrCounters->mRaRx);
cJSON_AddNumberToObject(ret, KEY_RATXSUCCESS, aBrCounters->mRaTxSuccess);
cJSON_AddNumberToObject(ret, KEY_RATXFAILED, aBrCounters->mRaTxFailure);
cJSON_AddNumberToObject(ret, KEY_RSRX, aBrCounters->mRsRx);
cJSON_AddNumberToObject(ret, KEY_RSTXSUCCESS, aBrCounters->mRsTxSuccess);
cJSON_AddNumberToObject(ret, KEY_RSTXFAILED, aBrCounters->mRsTxFailure);
return ret;
}
static cJSON *Diag2cJSON(const std::vector<otNetworkDiagTlv> &aDiagSet, std::set<std::string> aFieldset)
{
cJSON *diagInfoOfOneNode = cJSON_CreateObject();
cJSON *addrList = nullptr;
cJSON *tableList = nullptr;
uint64_t timeout;
for (auto diagTlv : aDiagSet)
{
switch (diagTlv.mType)
{
case OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS:
if (hasKey(aFieldset, KEY_EXTADDRESS))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_EXTADDRESS,
Bytes2HexJson(diagTlv.mData.mExtAddress.m8, OT_EXT_ADDRESS_SIZE));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS:
if (hasKey(aFieldset, KEY_RLOC16))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_RLOC16, Number2HexJson(diagTlv.mData.mAddr16));
}
if ((diagTlv.mData.mAddr16 & CHILD_MASK) == 0 && hasKey(aFieldset, KEY_ROUTERID))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_ROUTERID, cJSON_CreateNumber(diagTlv.mData.mAddr16 >> 10));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MODE:
if (hasKey(aFieldset, KEY_MODE))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_MODE, Mode2Json(diagTlv.mData.mMode));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT:
if (hasKey(aFieldset, KEY_TIMEOUT))
{
timeout = static_cast<uint64_t>(diagTlv.mData.mTimeout);
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_TIMEOUT, cJSON_CreateNumber(timeout));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY:
if (hasKey(aFieldset, KEY_CONNECTIVITY))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_CONNECTIVITY,
Connectivity2Json(diagTlv.mData.mConnectivity));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_ROUTE:
if (hasKey(aFieldset, KEY_ROUTE))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_ROUTE, Route2Json(diagTlv.mData.mRoute));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA:
if (hasKey(aFieldset, KEY_LEADERDATA))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_LEADERDATA, LeaderData2Json(diagTlv.mData.mLeaderData));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA:
if (hasKey(aFieldset, KEY_NETWORKDATA))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_NETWORKDATA,
Bytes2HexJson(diagTlv.mData.mNetworkData.m8, diagTlv.mData.mNetworkData.mCount));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST:
addrList = cJSON_CreateArray();
for (uint16_t i = 0; i < diagTlv.mData.mIp6AddrList.mCount; ++i)
{
cJSON_AddItemToArray(addrList, IpAddr2Json(diagTlv.mData.mIp6AddrList.mList[i]));
}
if (hasKey(aFieldset, KEY_IP6ADDRESSLIST))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_IP6ADDRESSLIST, addrList);
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS:
if (hasKey(aFieldset, KEY_MACCOUNTERS))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_MACCOUNTERS, MacCounters2Json(diagTlv.mData.mMacCounters));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL:
if (hasKey(aFieldset, KEY_BATTERYLEVEL))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_BATTERYLEVEL,
cJSON_CreateNumber(diagTlv.mData.mBatteryLevel));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE:
if (hasKey(aFieldset, KEY_SUPPLYVOLTAGE))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_SUPPLYVOLTAGE,
cJSON_CreateNumber(diagTlv.mData.mSupplyVoltage));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE:
tableList = cJSON_CreateArray();
for (uint16_t i = 0; i < diagTlv.mData.mChildTable.mCount; ++i)
{
cJSON_AddItemToArray(tableList, ChildTableEntry2Json(diagTlv.mData.mChildTable.mTable[i]));
}
if (hasKey(aFieldset, KEY_CHILDTABLE))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_CHILDTABLE, tableList);
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES:
if (hasKey(aFieldset, KEY_CHANNELPAGES))
{
cJSON_AddItemToObject(
diagInfoOfOneNode, KEY_CHANNELPAGES,
Bytes2HexJson(diagTlv.mData.mChannelPages.m8, diagTlv.mData.mChannelPages.mCount));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT:
if (hasKey(aFieldset, KEY_MAXCHILDTIMEOUT))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_MAXCHILDTIMEOUT,
cJSON_CreateNumber(diagTlv.mData.mMaxChildTimeout));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_EUI64:
if (hasKey(aFieldset, KEY_EUI))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_EUI,
Bytes2HexJson(diagTlv.mData.mEui64.m8, OT_EXT_ADDRESS_SIZE));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_VERSION:
if (hasKey(aFieldset, KEY_THREADVERSION))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_THREADVERSION, cJSON_CreateNumber(diagTlv.mData.mVersion));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_NAME:
if (hasKey(aFieldset, KEY_VENDORNAME))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_VENDORNAME,
cJSON_CreateString(&diagTlv.mData.mVendorName[0]));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_MODEL:
if (hasKey(aFieldset, KEY_VENDORMODEL))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_VENDORMODEL,
cJSON_CreateString(&diagTlv.mData.mVendorModel[0]));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_SW_VERSION:
if (hasKey(aFieldset, KEY_VENDORSWVERSION))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_VENDORSWVERSION,
cJSON_CreateString(&diagTlv.mData.mVendorSwVersion[0]));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_THREAD_STACK_VERSION:
if (hasKey(aFieldset, KEY_THREADSTACKVERSION))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_THREADSTACKVERSION,
cJSON_CreateString(&diagTlv.mData.mThreadStackVersion[0]));
}
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CHILD:
break;
case OT_NETWORK_DIAGNOSTIC_TLV_CHILD_IP6_ADDR_LIST:
break;
case OT_NETWORK_DIAGNOSTIC_TLV_ROUTER_NEIGHBOR:
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS:
if (hasKey(aFieldset, KEY_MLECOUNTERS))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_MLECOUNTERS, MleCounters2Json(diagTlv.mData.mMleCounters));
}
break;
default:
// unknown TLV type
break;
}
}
return diagInfoOfOneNode;
}
// TODO: simlify this interface
std::string DiagSet2JsonString(const std::vector<otNetworkDiagTlv> &aDiagSet,
std::vector<otMeshDiagChildEntry> aChildTable,
std::vector<DeviceIp6Addrs> aChildIps,
std::vector<otMeshDiagRouterNeighborEntry> aNeighbors,
const std::vector<networkDiagTlvExtensions> &aDiagTlvSetExtension,
std::set<std::string> aFieldset)
{
cJSON *diagInfoOfOneNode = nullptr;
cJSON *children = nullptr;
cJSON *childrenIpv6 = nullptr;
cJSON *neighbors = nullptr;
bool isRouter;
std::string ret;
diagInfoOfOneNode = Diag2cJSON(aDiagSet, aFieldset);
isRouter = cJSON_HasObjectItem(diagInfoOfOneNode, KEY_ROUTERID);
for (auto diagTlvExt : aDiagTlvSetExtension)
{
switch (diagTlvExt.mType)
{
case NETWORK_DIAGNOSTIC_TLVEXT_BR_COUNTER:
if (hasKey(aFieldset, KEY_BRCOUNTERS))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_BRCOUNTERS, brCounter2Json(&diagTlvExt.mData.mBrCounters));
}
break;
case NETWORK_DIAGNOSTIC_TLVEXT_SERVICEROLEFLAGS:
if (hasKey(aFieldset, KEY_ISLEADER))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_ISLEADER,
cJSON_CreateBool(diagTlvExt.mData.mServiceRoleFlags.mIsLeader));
}
if (hasKey(aFieldset, KEY_SERVICE))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_SERVICE,
cJSON_CreateBool(diagTlvExt.mData.mServiceRoleFlags.mHostsService));
}
if (hasKey(aFieldset, KEY_ISPBBR))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_ISPBBR,
cJSON_CreateBool(diagTlvExt.mData.mServiceRoleFlags.mIsPrimaryBBR));
}
if (hasKey(aFieldset, KEY_ISBR))
{
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_ISBR,
cJSON_CreateBool(diagTlvExt.mData.mServiceRoleFlags.mIsBorderRouter));
}
break;
case NETWORK_DIAGNOSTIC_TLVEXT_CHILDREN:
if (hasKey(aFieldset, KEY_CHILDREN) && isRouter)
{
children = MeshChildTable2Json(aChildTable);
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_CHILDREN, children);
}
break;
case NETWORK_DIAGNOSTIC_TLVEXT_CHILDRENIP6:
if (hasKey(aFieldset, KEY_CHILDIPV6ADDRESSES) && isRouter)
{
childrenIpv6 = MeshChildrenIp62Json(aChildIps);
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_CHILDIPV6ADDRESSES, childrenIpv6);
}
break;
case NETWORK_DIAGNOSTIC_TLVEXT_ROUTERNEIGHBORS:
if (hasKey(aFieldset, KEY_ROUTERNEIGHBORS) && isRouter)
{
neighbors = MeshRouterNeighbors2Json(aNeighbors);
cJSON_AddItemToObject(diagInfoOfOneNode, KEY_ROUTERNEIGHBORS, neighbors);
}
break;
default:
// unknown TLV type
break;
}
}
ret = Json2String(diagInfoOfOneNode);
cJSON_Delete(diagInfoOfOneNode);
return ret;
}
std::string jsonStr2JsonApiItem(std::string aId, const std::string aType, std::string aAttribute)
{
cJSON *root = cJSON_CreateObject();
std::string ret;
cJSON_AddStringToObject(root, KEY_ID, aId.c_str());
cJSON_AddStringToObject(root, KEY_TYPE, aType.c_str());
cJSON_AddItemToObject(root, KEY_ATTRIBUTES, cJSON_Parse(aAttribute.c_str()));
ret = Json2String(root);
cJSON_Delete(root);
return ret;
}
std::string jsonStr2JsonApiItem(std::string aId, const std::string aType, std::string aAttribute, cJSON *aRelationship)
{
cJSON *root = cJSON_CreateObject();
std::string ret;
cJSON_AddStringToObject(root, KEY_ID, aId.c_str());
cJSON_AddStringToObject(root, KEY_TYPE, aType.c_str());
cJSON_AddItemToObject(root, KEY_ATTRIBUTES, cJSON_Parse(aAttribute.c_str()));
cJSON_AddItemToObject(root, KEY_RELATIONSHIPS, cJSON_Duplicate(aRelationship, true));
ret = Json2String(root);
cJSON_Delete(root);
return ret;
}
std::string jsonStr2JsonApiColl(std::string data, std::string meta)
{
cJSON *root = cJSON_CreateObject();
std::string ret;
cJSON_AddItemToObject(root, KEY_DATA, cJSON_Parse(data.c_str()));
if (meta.length() > 0)
{
cJSON_AddItemToObject(root, KEY_META, cJSON_Parse(meta.c_str()));
}
ret = Json2String(root);
cJSON_Delete(root);
return ret;
}
static cJSON *DeviceInfo2Json(const DeviceInfo &aDeviceInfo, std::set<std::string> aFieldset)
{
cJSON *deviceInfo = cJSON_CreateObject();
if (hasKey(aFieldset, KEY_EXTADDRESS))
{
cJSON_AddItemToObject(deviceInfo, KEY_EXTADDRESS,
Bytes2HexJson(aDeviceInfo.mExtAddress.m8, OT_EXT_ADDRESS_SIZE));
}
if (hasKey(aFieldset, KEY_MLEIDIID))
{
cJSON_AddItemToObject(deviceInfo, KEY_MLEIDIID, Bytes2HexJson(aDeviceInfo.mMlEidIid.m8, OT_EXT_ADDRESS_SIZE));
}
if (hasKey(aFieldset, KEY_OMRIPV6))
{
cJSON_AddItemToObject(deviceInfo, KEY_OMRIPV6, IpAddr2Json(aDeviceInfo.mIp6Addr));
}
// if (hasKey(aFieldset, KEY_EUI))
// {
// cJSON_AddItemToObject(deviceInfo, KEY_EUI, Bytes2HexJson(aDeviceInfo.mEui64.m8, OT_EXT_ADDRESS_SIZE));
// }
if (hasKey(aFieldset, KEY_HOSTNAME))
{
cJSON_AddItemToObject(deviceInfo, KEY_HOSTNAME, cJSON_CreateString(aDeviceInfo.mHostName.c_str()));
}
if (hasKey(aFieldset, KEY_ROLE))
{
cJSON_AddItemToObject(deviceInfo, KEY_ROLE, cJSON_CreateString(aDeviceInfo.mRole.c_str()));
}
if (hasToplevelKey(aFieldset, KEY_MODE))
{
cJSON *mode = cJSON_CreateObject();
if (hasKey(aFieldset, concat(KEY_MODE, KEY_ISFTD)))
{
cJSON_AddItemToObject(mode, KEY_ISFTD, cJSON_CreateBool(aDeviceInfo.mode.mDeviceType));
}
if (hasKey(aFieldset, concat(KEY_MODE, KEY_RXONWHENIDLE)))
{
cJSON_AddItemToObject(mode, KEY_RXONWHENIDLE, cJSON_CreateBool(aDeviceInfo.mode.mRxOnWhenIdle));
}
if (hasKey(aFieldset, concat(KEY_MODE, KEY_FULLNETWORKDATA)))
{
cJSON_AddItemToObject(mode, KEY_FULLNETWORKDATA, cJSON_CreateBool(aDeviceInfo.mode.mNetworkData));
}
cJSON_AddItemToObject(deviceInfo, KEY_MODE, mode);
}
return deviceInfo;
}
std::string DeviceInfo2JsonString(const DeviceInfo &aDeviceInfo)
{
std::string ret;
std::set<std::string> fieldset;
cJSON *json = DeviceInfo2Json(aDeviceInfo, fieldset);
ret = Json2String(json);
cJSON_Delete(json);
return ret;
}
std::string SparseDeviceInfo2JsonString(const DeviceInfo &aDeviceInfo, std::set<std::string> aFieldset)
{
std::string ret;
cJSON *json = DeviceInfo2Json(aDeviceInfo, aFieldset);
ret = Json2String(json);
cJSON_Delete(json);
return ret;
}
std::string Bytes2HexJsonString(const uint8_t *aBytes, uint8_t aLength)
{
cJSON *hex = Bytes2HexJson(aBytes, aLength);
std::string ret = Json2String(hex);
cJSON_Delete(hex);
return ret;
}
int Hex2BytesJsonString(const std::string &aHexString, uint8_t *aBytes, uint8_t aMaxLength)
{
return otbr::Utils::Hex2Bytes(aHexString.c_str(), aBytes, aMaxLength);
}
std::string Number2JsonString(const uint32_t &aNumber)
{
cJSON *number = cJSON_CreateNumber(aNumber);
std::string ret = Json2String(number);
cJSON_Delete(number);
return ret;
}
std::string Mode2JsonString(const otLinkModeConfig &aMode)
{
cJSON *mode = Mode2Json(aMode);
std::string ret = Json2String(mode);
cJSON_Delete(mode);
return ret;
}
std::string Connectivity2JsonString(const otNetworkDiagConnectivity &aConnectivity)
{
cJSON *connectivity = Connectivity2Json(aConnectivity);
std::string ret = Json2String(connectivity);
cJSON_Delete(connectivity);
return ret;
}
std::string RouteData2JsonString(const otNetworkDiagRouteData &aRouteData)
{
cJSON *routeData = RouteData2Json(aRouteData);
std::string ret = Json2String(routeData);
cJSON_Delete(routeData);
return ret;
}
std::string Route2JsonString(const otNetworkDiagRoute &aRoute)
{
cJSON *route = Route2Json(aRoute);
std::string ret = Json2String(route);
cJSON_Delete(route);
return ret;
}
std::string LeaderData2JsonString(const otLeaderData &aLeaderData)
{
cJSON *leaderData = LeaderData2Json(aLeaderData);
std::string ret = Json2String(leaderData);
cJSON_Delete(leaderData);
return ret;
}
std::string MacCounters2JsonString(const otNetworkDiagMacCounters &aMacCounters)
{
cJSON *macCounters = MacCounters2Json(aMacCounters);
std::string ret = Json2String(macCounters);
cJSON_Delete(macCounters);
return ret;
}
std::string ChildTableEntry2JsonString(const otNetworkDiagChildEntry &aChildEntry)
{
cJSON *childEntry = ChildTableEntry2Json(aChildEntry);
std::string ret = Json2String(childEntry);
cJSON_Delete(childEntry);
return ret;
}
std::string CString2JsonString(const char *aCString)
{
cJSON *cString = CString2Json(aCString);
std::string ret = Json2String(cString);
cJSON_Delete(cString);
return ret;
}
std::string Error2JsonString(httplib::StatusCode aErrorCode, std::string aErrorMessage)
{
std::string ret;
cJSON *error = cJSON_CreateObject();
cJSON_AddItemToObject(error, KEY_TITLE, cJSON_CreateString(aErrorMessage.c_str()));
cJSON_AddItemToObject(error, KEY_STATUS, cJSON_CreateNumber(static_cast<int16_t>(aErrorCode)));
ret = Json2String(error);
cJSON_Delete(error);
return ret;
}
std::string ErrorDetails2JsonString(httplib::StatusCode aErrorCode,
std::string aErrorMessage,
std::string aErrorDetails)
{
std::string ret;
cJSON *error = cJSON_CreateObject();
cJSON_AddItemToObject(error, KEY_TITLE, cJSON_CreateString(aErrorMessage.c_str()));
cJSON_AddItemToObject(error, KEY_STATUS, cJSON_CreateNumber(static_cast<int16_t>(aErrorCode)));
cJSON_AddItemToObject(error, KEY_DETAIL, cJSON_CreateString(aErrorDetails.c_str()));
ret = Json2String(error);
cJSON_Delete(error);
return ret;
}
cJSON *ActiveDataset2Json(const otOperationalDataset &aActiveDataset)
{
cJSON *node = cJSON_CreateObject();
if (aActiveDataset.mComponents.mIsActiveTimestampPresent)
{
cJSON_AddItemToObject(node, KEY_ACTIVETIMESTAMP, Timestamp2Json(aActiveDataset.mActiveTimestamp));
}
if (aActiveDataset.mComponents.mIsNetworkKeyPresent)
{
cJSON_AddItemToObject(node, KEY_NETWORKKEY, Bytes2HexJson(aActiveDataset.mNetworkKey.m8, OT_NETWORK_KEY_SIZE));
}
if (aActiveDataset.mComponents.mIsNetworkNamePresent)
{
cJSON_AddItemToObject(node, KEY_NETWORKNAME, cJSON_CreateString(aActiveDataset.mNetworkName.m8));
}
if (aActiveDataset.mComponents.mIsExtendedPanIdPresent)
{
cJSON_AddItemToObject(node, KEY_EXTPANID, Bytes2HexJson(aActiveDataset.mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE));
}
if (aActiveDataset.mComponents.mIsMeshLocalPrefixPresent)
{
cJSON_AddItemToObject(node, KEY_MESHLOCALPREFIX, IpPrefix2Json(aActiveDataset.mMeshLocalPrefix));
}
if (aActiveDataset.mComponents.mIsPanIdPresent)
{
cJSON_AddItemToObject(node, KEY_PANID, cJSON_CreateNumber(aActiveDataset.mPanId));
}
if (aActiveDataset.mComponents.mIsChannelPresent)
{
cJSON_AddItemToObject(node, KEY_CHANNEL, cJSON_CreateNumber(aActiveDataset.mChannel));
}
if (aActiveDataset.mComponents.mIsPskcPresent)
{
cJSON_AddItemToObject(node, KEY_PSKC, Bytes2HexJson(aActiveDataset.mPskc.m8, OT_PSKC_MAX_SIZE));
}
if (aActiveDataset.mComponents.mIsSecurityPolicyPresent)
{
cJSON_AddItemToObject(node, KEY_SECURITYPOLICY, SecurityPolicy2Json(aActiveDataset.mSecurityPolicy));
}
if (aActiveDataset.mComponents.mIsChannelMaskPresent)
{
cJSON_AddItemToObject(node, KEY_CHANNELMASK, cJSON_CreateNumber(aActiveDataset.mChannelMask));
}
return node;
}
std::string ActiveDataset2JsonString(const otOperationalDataset &aActiveDataset)
{
cJSON *node;
std::string ret;
node = ActiveDataset2Json(aActiveDataset);
ret = Json2String(node);
cJSON_Delete(node);
return ret;
}
std::string PendingDataset2JsonString(const otOperationalDataset &aPendingDataset)
{
cJSON *nodeActiveDataset;
cJSON *node = cJSON_CreateObject();
std::string ret;
nodeActiveDataset = ActiveDataset2Json(aPendingDataset);
cJSON_AddItemToObject(node, KEY_ACTIVEDATASET, nodeActiveDataset);
if (aPendingDataset.mComponents.mIsPendingTimestampPresent)
{
cJSON_AddItemToObject(node, KEY_PENDINGTIMESTAMP, Timestamp2Json(aPendingDataset.mPendingTimestamp));
}
if (aPendingDataset.mComponents.mIsDelayPresent)
{
cJSON_AddItemToObject(node, KEY_DELAY, cJSON_CreateNumber(aPendingDataset.mDelay));
}
ret = Json2String(node);
cJSON_Delete(node);
return ret;
}
bool JsonActiveDataset2Dataset(const cJSON *jsonActiveDataset, otOperationalDataset &aDataset)
{
cJSON *value;
otTimestamp timestamp;
bool ret = true;
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_ACTIVETIMESTAMP);
if (cJSON_IsObject(value))
{
VerifyOrExit(Json2Timestamp(value, timestamp), ret = false);
aDataset.mActiveTimestamp = timestamp;
aDataset.mComponents.mIsActiveTimestampPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsActiveTimestampPresent = false;
}
else if (value != nullptr)
{
ExitNow(ret = false);
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_NETWORKKEY);
if (cJSON_IsString(value))
{
VerifyOrExit(value->valuestring != nullptr, ret = false);
VerifyOrExit(Hex2BytesJsonString(std::string(value->valuestring), aDataset.mNetworkKey.m8,
OT_NETWORK_KEY_SIZE) == OT_NETWORK_KEY_SIZE,
ret = false);
aDataset.mComponents.mIsNetworkKeyPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsNetworkKeyPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_NETWORKNAME);
if (cJSON_IsString(value))
{
VerifyOrExit(value->valuestring != nullptr, ret = false);
VerifyOrExit(strlen(value->valuestring) <= OT_NETWORK_NAME_MAX_SIZE, ret = false);
strncpy(aDataset.mNetworkName.m8, value->valuestring, OT_NETWORK_NAME_MAX_SIZE);
aDataset.mComponents.mIsNetworkNamePresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsNetworkNamePresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_EXTPANID);
if (cJSON_IsString(value))
{
VerifyOrExit(value->valuestring != nullptr, ret = false);
VerifyOrExit(Hex2BytesJsonString(std::string(value->valuestring), aDataset.mExtendedPanId.m8,
OT_EXT_PAN_ID_SIZE) == OT_EXT_PAN_ID_SIZE,
ret = false);
aDataset.mComponents.mIsExtendedPanIdPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsExtendedPanIdPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_MESHLOCALPREFIX);
if (cJSON_IsString(value))
{
VerifyOrExit(value->valuestring != nullptr, ret = false);
VerifyOrExit(Json2IpPrefix(value, aDataset.mMeshLocalPrefix) == OTBR_ERROR_NONE, ret = false);
aDataset.mComponents.mIsMeshLocalPrefixPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsMeshLocalPrefixPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_PANID);
if (cJSON_IsNumber(value))
{
aDataset.mPanId = static_cast<otPanId>(value->valueint);
aDataset.mComponents.mIsPanIdPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsPanIdPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_CHANNEL);
if (cJSON_IsNumber(value))
{
aDataset.mChannel = static_cast<uint16_t>(value->valueint);
aDataset.mComponents.mIsChannelPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsChannelPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_PSKC);
if (cJSON_IsString(value))
{
VerifyOrExit(value->valuestring != nullptr, ret = false);
VerifyOrExit(Hex2BytesJsonString(std::string(value->valuestring), aDataset.mPskc.m8, OT_PSKC_MAX_SIZE) ==
OT_PSKC_MAX_SIZE,
ret = false);
aDataset.mComponents.mIsPskcPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsPskcPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_SECURITYPOLICY);
if (cJSON_IsObject(value))
{
VerifyOrExit(Json2SecurityPolicy(value, aDataset.mSecurityPolicy), ret = false);
aDataset.mComponents.mIsSecurityPolicyPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsSecurityPolicyPresent = false;
}
value = cJSON_GetObjectItemCaseSensitive(jsonActiveDataset, KEY_CHANNELMASK);
if (cJSON_IsNumber(value))
{
aDataset.mChannelMask = value->valueint;
aDataset.mComponents.mIsChannelMaskPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsChannelMaskPresent = false;
}
exit:
return ret;
}
bool JsonActiveDatasetString2Dataset(const std::string &aJsonActiveDataset, otOperationalDataset &aDataset)
{
cJSON *jsonActiveDataset;
bool ret = true;
VerifyOrExit((jsonActiveDataset = cJSON_Parse(aJsonActiveDataset.c_str())) != nullptr, ret = false);
VerifyOrExit(cJSON_IsObject(jsonActiveDataset), ret = false);
ret = JsonActiveDataset2Dataset(jsonActiveDataset, aDataset);
exit:
cJSON_Delete(jsonActiveDataset);
return ret;
}
bool JsonPendingDatasetString2Dataset(const std::string &aJsonPendingDataset, otOperationalDataset &aDataset)
{
cJSON *value;
cJSON *jsonDataset;
otTimestamp timestamp;
bool ret = true;
VerifyOrExit((jsonDataset = cJSON_Parse(aJsonPendingDataset.c_str())) != nullptr, ret = false);
VerifyOrExit(cJSON_IsObject(jsonDataset), ret = false);
value = cJSON_GetObjectItemCaseSensitive(jsonDataset, KEY_ACTIVEDATASET);
if (cJSON_IsObject(value))
{
VerifyOrExit(JsonActiveDataset2Dataset(value, aDataset), ret = false);
}
else if (cJSON_IsString(value))
{
otOperationalDatasetTlvs datasetTlvs;
int len;
len =
Hex2BytesJsonString(std::string(value->valuestring), datasetTlvs.mTlvs, OT_OPERATIONAL_DATASET_MAX_LENGTH);
VerifyOrExit(len > 0, ret = false);
datasetTlvs.mLength = len;
VerifyOrExit(otDatasetParseTlvs(&datasetTlvs, &aDataset) == OT_ERROR_NONE, ret = false);
}
else
{
ExitNow(ret = false);
}
value = cJSON_GetObjectItemCaseSensitive(jsonDataset, KEY_PENDINGTIMESTAMP);
if (cJSON_IsObject(value))
{
VerifyOrExit(Json2Timestamp(value, timestamp), ret = false);
aDataset.mPendingTimestamp = timestamp;
aDataset.mComponents.mIsPendingTimestampPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsPendingTimestampPresent = false;
}
else if (value != nullptr)
{
ExitNow(ret = false);
}
value = cJSON_GetObjectItemCaseSensitive(jsonDataset, KEY_DELAY);
if (cJSON_IsNumber(value))
{
aDataset.mDelay = value->valueint;
aDataset.mComponents.mIsDelayPresent = true;
}
else if (cJSON_IsNull(value))
{
aDataset.mComponents.mIsDelayPresent = false;
}
exit:
cJSON_Delete(jsonDataset);
return ret;
}
cJSON *JoinerInfo2Json(const otJoinerInfo &aJoinerInfo)
{
cJSON *node = cJSON_CreateObject();
cJSON_AddItemToObject(node, KEY_PSKD, cJSON_CreateString(aJoinerInfo.mPskd.m8));
if (aJoinerInfo.mType == OT_JOINER_INFO_TYPE_EUI64)
{
cJSON_AddItemToObject(node, KEY_EUI, Bytes2HexJson(aJoinerInfo.mSharedId.mEui64.m8, OT_EXT_ADDRESS_SIZE));
}
else if (aJoinerInfo.mType == OT_JOINER_INFO_TYPE_DISCERNER)
{
char hexValue[((OT_JOINER_MAX_DISCERNER_LENGTH / 8) * 2) + 1] = {0};
char string[sizeof("0x") + ((OT_JOINER_MAX_DISCERNER_LENGTH / 8) * 2) + sizeof("/xx") + 1] = {0};
otbr::Utils::Long2Hex(aJoinerInfo.mSharedId.mDiscerner.mValue, hexValue);
snprintf(string, sizeof(string), "0x%s/%d", hexValue, aJoinerInfo.mSharedId.mDiscerner.mLength);
cJSON_AddItemToObject(node, KEY_DISCERNER, cJSON_CreateString(string));
}
else
{
cJSON_AddItemToObject(node, KEY_JOINERID, cJSON_CreateString("*"));
}
cJSON_AddItemToObject(node, KEY_TIMEOUT, cJSON_CreateNumber(aJoinerInfo.mExpirationTime));
return node;
}
std::string JoinerInfo2JsonString(const otJoinerInfo &aJoinerInfo)
{
cJSON *node;
std::string ret;
node = JoinerInfo2Json(aJoinerInfo);
ret = Json2String(node);
cJSON_Delete(node);
return ret;
}
static cJSON *AddDevice2Json(const std::string &aEui, const std::string &aPskd, std::set<std::string> aFieldset)
{
cJSON *root = cJSON_CreateObject();
if (hasKey(aFieldset, KEY_EUI))
{
cJSON_AddItemToObject(root, KEY_EUI, cJSON_CreateString(aEui.c_str()));
}
if (hasKey(aFieldset, KEY_PSKD))
{
cJSON_AddItemToObject(root, KEY_PSKD, cJSON_CreateString(aPskd.c_str()));
}
return root;
}
std::string AddDevice2JsonString(const std::string &aEui, const std::string &aPskd)
{
std::string ret;
std::set<std::string> fieldset;
cJSON *json = AddDevice2Json(aEui, aPskd, fieldset);
ret = Json2String(json);
cJSON_Delete(json);
return ret;
}
std::string SparseAddDevice2JsonString(const std::string &aEui,
const std::string &aPskd,
std::set<std::string> aFieldset)
{
std::string ret;
cJSON *json = AddDevice2Json(aEui, aPskd, aFieldset);
ret = Json2String(json);
cJSON_Delete(json);
return ret;
}
otbrError StringDiscerner2Discerner(char *aString, otJoinerDiscerner &aDiscerner)
{
otbrError error = OTBR_ERROR_NONE;
char *separator;
uint8_t byteLength;
uint8_t byteSwapBuffer[OT_JOINER_MAX_DISCERNER_LENGTH / BITS_PER_BYTE] = {0};
uint8_t *buffer = (uint8_t *)&aDiscerner.mValue;
separator = strstr(aString, "/");
VerifyOrExit(separator != nullptr, error = OTBR_ERROR_NOT_FOUND);
VerifyOrExit(sscanf(separator + 1, "%hhu", &aDiscerner.mLength) == 1, error = OTBR_ERROR_INVALID_ARGS);
VerifyOrExit(aDiscerner.mLength > 0 && aDiscerner.mLength <= OT_JOINER_MAX_DISCERNER_LENGTH,
error = OTBR_ERROR_INVALID_ARGS);
if (memcmp(aString, "0x", 2) == 0)
{
aString += 2;
}
*separator = '\0';
byteLength =
Hex2BytesJsonString(std::string(aString), byteSwapBuffer, OT_JOINER_MAX_DISCERNER_LENGTH / BITS_PER_BYTE);
VerifyOrExit(byteLength <= (1 + ((aDiscerner.mLength - 1) / BITS_PER_BYTE)), error = OTBR_ERROR_INVALID_ARGS);
// The discerner is expected to be big endian
for (uint8_t i = 0; i < byteLength; i++)
{
buffer[i] = byteSwapBuffer[byteLength - i - 1];
}
exit:
return error;
}
bool JsonJoinerInfo2JoinerInfo(const cJSON *jsonJoinerInfo, otJoinerInfo &aJoinerInfo)
{
cJSON *value;
bool ret = false;
aJoinerInfo.mType = OT_JOINER_INFO_TYPE_ANY;
memset(&aJoinerInfo.mSharedId.mEui64, 0, sizeof(aJoinerInfo.mSharedId.mEui64));
memset(&aJoinerInfo.mPskd.m8, 0, sizeof(aJoinerInfo.mPskd.m8));
value = cJSON_GetObjectItemCaseSensitive(jsonJoinerInfo, KEY_PSKD);
if (cJSON_IsString(value))
{
VerifyOrExit(value->valuestring != nullptr);
VerifyOrExit(strlen(value->valuestring) <= OT_JOINER_MAX_PSKD_LENGTH);
strncpy(aJoinerInfo.mPskd.m8, value->valuestring, OT_JOINER_MAX_PSKD_LENGTH);
}
else
{
ExitNow();
}
value = cJSON_GetObjectItemCaseSensitive(jsonJoinerInfo, KEY_JOINERID);
if (cJSON_IsString(value))
{
VerifyOrExit(aJoinerInfo.mType == OT_JOINER_INFO_TYPE_ANY);
VerifyOrExit(value->valuestring != nullptr);
if (strncmp(value->valuestring, "*", 1) != 0)
{
otbrError err = StringDiscerner2Discerner(value->valuestring, aJoinerInfo.mSharedId.mDiscerner);
if (err == OTBR_ERROR_NOT_FOUND)
{
VerifyOrExit(Hex2BytesJsonString(std::string(value->valuestring), aJoinerInfo.mSharedId.mEui64.m8,
OT_EXT_ADDRESS_SIZE) == OT_EXT_ADDRESS_SIZE);
aJoinerInfo.mType = OT_JOINER_INFO_TYPE_EUI64;
}
else
{
VerifyOrExit(err == OTBR_ERROR_NONE);
aJoinerInfo.mType = OT_JOINER_INFO_TYPE_DISCERNER;
}
}
}
value = cJSON_GetObjectItemCaseSensitive(jsonJoinerInfo, KEY_DISCERNER);
if (cJSON_IsString(value))
{
VerifyOrExit(aJoinerInfo.mType == OT_JOINER_INFO_TYPE_ANY);
VerifyOrExit(value->valuestring != nullptr);
if (strncmp(value->valuestring, "*", 1) != 0)
{
VerifyOrExit(StringDiscerner2Discerner(value->valuestring, aJoinerInfo.mSharedId.mDiscerner) ==
OTBR_ERROR_NONE);
aJoinerInfo.mType = OT_JOINER_INFO_TYPE_DISCERNER;
}
}
value = cJSON_GetObjectItemCaseSensitive(jsonJoinerInfo, KEY_EUI);
if (cJSON_IsString(value))
{
VerifyOrExit(aJoinerInfo.mType == OT_JOINER_INFO_TYPE_ANY);
VerifyOrExit(value->valuestring != nullptr);
if (strncmp(value->valuestring, "*", 1) != 0)
{
VerifyOrExit(Hex2BytesJsonString(std::string(value->valuestring), aJoinerInfo.mSharedId.mEui64.m8,
OT_EXT_ADDRESS_SIZE) == OT_EXT_ADDRESS_SIZE);
aJoinerInfo.mType = OT_JOINER_INFO_TYPE_EUI64;
}
}
aJoinerInfo.mExpirationTime = 60;
value = cJSON_GetObjectItemCaseSensitive(jsonJoinerInfo, KEY_TIMEOUT);
if (cJSON_IsNumber(value))
{
aJoinerInfo.mExpirationTime = value->valueint;
}
ret = true;
exit:
return ret;
}
bool JsonJoinerInfoString2JoinerInfo(const std::string &aJsonJoinerInfo, otJoinerInfo &aJoinerInfo)
{
cJSON *jsonJoinerInfo;
bool ret = true;
VerifyOrExit((jsonJoinerInfo = cJSON_Parse(aJsonJoinerInfo.c_str())) != nullptr, ret = false);
VerifyOrExit(cJSON_IsObject(jsonJoinerInfo), ret = false);
ret = JsonJoinerInfo2JoinerInfo(jsonJoinerInfo, aJoinerInfo);
exit:
cJSON_Delete(jsonJoinerInfo);
return ret;
}
static cJSON *EnergyReport2Json(const EnergyScanReport &aReport, std::set<std::string> aFieldset)
{
cJSON *root = cJSON_CreateObject();
cJSON *channels;
cJSON *chitem;
cJSON *energy;
if (hasKey(aFieldset, KEY_ORIGIN))
{
cJSON_AddItemToObject(root, KEY_ORIGIN, Bytes2HexJson(aReport.mOrigin.mFields.m8, OT_EXT_ADDRESS_SIZE));
}
if (hasToplevelKey(aFieldset, KEY_REPORT))
{
channels = cJSON_CreateArray();
for (const auto &it : aReport.mReports)
{
chitem = cJSON_CreateObject();
if (hasKey(aFieldset, concat(KEY_REPORT, KEY_CHANNEL)))
{
cJSON_AddItemToObject(chitem, KEY_CHANNEL, cJSON_CreateNumber(it.mChannel));
}
if (hasKey(aFieldset, concat(KEY_REPORT, KEY_MAXRSSI)))
{
energy = cJSON_CreateArray();
for (const auto &itRssi : it.mMaxRssi)
{
cJSON_AddItemToArray(energy, cJSON_CreateNumber(itRssi));
}
cJSON_AddItemToObject(chitem, KEY_MAXRSSI, energy);
}
cJSON_AddItemToArray(channels, chitem);
}
cJSON_AddItemToObject(root, KEY_REPORT, channels);
}
return root;
}
std::string EnergyReport2JsonString(const EnergyScanReport &aReport)
{
std::string ret;
std::set<std::string> fieldset;
cJSON *json = EnergyReport2Json(aReport, fieldset);
ret = Json2String(json);
cJSON_Delete(json);
return ret;
}
std::string SparseEnergyReport2JsonString(const EnergyScanReport &aReport, std::set<std::string> aFieldset)
{
std::string ret;
cJSON *json = EnergyReport2Json(aReport, aFieldset);
ret = Json2String(json);
cJSON_Delete(json);
return ret;
}
cJSON *JoinerTable2Json(const std::vector<otJoinerInfo> &aJoinerTable)
{
cJSON *table = cJSON_CreateArray();
for (const otJoinerInfo joiner : aJoinerTable)
{
cJSON *joinerJson = JoinerInfo2Json(joiner);
cJSON_AddItemToArray(table, joinerJson);
}
return table;
}
std::string JoinerTable2JsonString(const std::vector<otJoinerInfo> &aJoinerTable)
{
return Json2String(JoinerTable2Json(aJoinerTable));
}
static cJSON *MeshChildEntry2Json(const otMeshDiagChildEntry &aChild)
{
cJSON *child = cJSON_CreateObject();
cJSON_AddItemToObject(child, KEY_RXONWHENIDLE, cJSON_CreateBool(aChild.mRxOnWhenIdle));
cJSON_AddItemToObject(child, KEY_ISFTD, cJSON_CreateBool(aChild.mDeviceTypeFtd));
cJSON_AddItemToObject(child, KEY_FULLNETWORKDATA, cJSON_CreateBool(aChild.mFullNetData));
cJSON_AddItemToObject(child, KEY_CSLSYNCHRONIZED, cJSON_CreateBool(aChild.mCslSynchronized));
cJSON_AddItemToObject(child, KEY_SUPPORTSERRORRATE, cJSON_CreateBool(aChild.mSupportsErrRate));
cJSON_AddItemToObject(child, KEY_RLOC16, Number2HexJson(aChild.mRloc16));
cJSON_AddItemToObject(child, KEY_CHILDID, cJSON_CreateNumber(aChild.mRloc16 & CHILD_MASK));
cJSON_AddItemToObject(child, KEY_EXTADDRESS, Bytes2HexJson(aChild.mExtAddress.m8, OT_EXT_ADDRESS_SIZE));
cJSON_AddItemToObject(child, KEY_THREADVERSION, cJSON_CreateNumber(aChild.mVersion));
cJSON_AddItemToObject(child, KEY_TIMEOUT, cJSON_CreateNumber(aChild.mTimeout));
cJSON_AddItemToObject(child, KEY_AGE, cJSON_CreateNumber(aChild.mAge));
cJSON_AddItemToObject(child, KEY_LINKAGE, cJSON_CreateNumber(aChild.mConnectionTime));
if (aChild.mSupervisionInterval != 0)
{
cJSON_AddItemToObject(child, KEY_SUPERVISIONINTERVAL, cJSON_CreateNumber(aChild.mSupervisionInterval));
}
cJSON_AddItemToObject(child, KEY_LINKMARGIN, cJSON_CreateNumber(aChild.mLinkMargin));
cJSON_AddItemToObject(child, KEY_AVERAGERSSI, cJSON_CreateNumber(aChild.mAverageRssi));
cJSON_AddItemToObject(child, KEY_LASTRSSI, cJSON_CreateNumber(aChild.mLastRssi));
if (aChild.mSupportsErrRate)
{
float errRate;
errRate = static_cast<float>(aChild.mFrameErrorRate) / static_cast<float>(0xFFFF);
cJSON_AddItemToObject(child, KEY_FRAMEERRORRATE, cJSON_CreateNumber(errRate));
errRate = static_cast<float>(aChild.mMessageErrorRate) / static_cast<float>(0xFFFF);
cJSON_AddItemToObject(child, KEY_MESSAGEERRORRATE, cJSON_CreateNumber(errRate));
}
cJSON_AddItemToObject(child, KEY_QUEUEDMESSAGECOUNT, cJSON_CreateNumber(aChild.mQueuedMessageCount));
if (aChild.mCslSynchronized)
{
cJSON_AddItemToObject(child, KEY_CSLPERIOD, cJSON_CreateNumber(aChild.mCslPeriod));
cJSON_AddItemToObject(child, KEY_CSLTIMEOUT, cJSON_CreateNumber(aChild.mCslTimeout));
cJSON_AddItemToObject(child, KEY_CSLCHANNEL, cJSON_CreateNumber(aChild.mCslChannel));
}
return child;
}
static cJSON *MeshChildTable2Json(const std::vector<otMeshDiagChildEntry> &aChildren)
{
cJSON *json = cJSON_CreateArray();
for (const otMeshDiagChildEntry &child : aChildren)
{
cJSON_AddItemToArray(json, MeshChildEntry2Json(child));
}
return json;
}
static cJSON *MeshChildIp62Json(const DeviceIp6Addrs &aChildIp6Addrs)
{
cJSON *child = cJSON_CreateObject();
cJSON_AddItemToObject(child, KEY_RLOC16, Number2HexJson(aChildIp6Addrs.mRloc16));
// cJSON_AddItemToObject(child, KEY_EXTADDRESS, Bytes2HexJson(aChild.mExtAddress.m8, OT_EXT_ADDRESS_SIZE));
cJSON *ips = cJSON_CreateArray();
for (const otIp6Address ipaddr : aChildIp6Addrs.mIp6Addrs)
{
cJSON_AddItemToArray(ips, IpAddr2Json(ipaddr));
}
cJSON_AddItemToObject(child, KEY_IP6ADDRESSLIST, ips);
return child;
}
static cJSON *MeshChildrenIp62Json(const std::vector<DeviceIp6Addrs> &aChildrenIp6Addrs)
{
cJSON *json = cJSON_CreateArray();
for (const DeviceIp6Addrs &child : aChildrenIp6Addrs)
{
cJSON_AddItemToArray(json, MeshChildIp62Json(child));
}
return json;
}
static cJSON *MeshRouterNeighborEntry2Json(const otMeshDiagRouterNeighborEntry &aNeighbor)
{
cJSON *neighbor = cJSON_CreateObject();
cJSON_AddItemToObject(neighbor, KEY_SUPPORTSERRORRATE, cJSON_CreateBool(aNeighbor.mSupportsErrRate));
cJSON_AddItemToObject(neighbor, KEY_RLOC16, Number2HexJson(aNeighbor.mRloc16));
cJSON_AddItemToObject(neighbor, KEY_EXTADDRESS, Bytes2HexJson(aNeighbor.mExtAddress.m8, OT_EXT_ADDRESS_SIZE));
cJSON_AddItemToObject(neighbor, KEY_THREADVERSION, cJSON_CreateNumber(aNeighbor.mVersion));
cJSON_AddItemToObject(neighbor, KEY_LINKAGE, cJSON_CreateNumber(aNeighbor.mConnectionTime));
cJSON_AddItemToObject(neighbor, KEY_LINKMARGIN, cJSON_CreateNumber(aNeighbor.mLinkMargin));
cJSON_AddItemToObject(neighbor, KEY_AVERAGERSSI, cJSON_CreateNumber(aNeighbor.mAverageRssi));
cJSON_AddItemToObject(neighbor, KEY_LASTRSSI, cJSON_CreateNumber(aNeighbor.mLastRssi));
if (aNeighbor.mSupportsErrRate)
{
float errRate;
errRate = static_cast<float>(aNeighbor.mFrameErrorRate) / static_cast<float>(0xFFFF);
cJSON_AddItemToObject(neighbor, KEY_FRAMEERRORRATE, cJSON_CreateNumber(errRate));
errRate = static_cast<float>(aNeighbor.mMessageErrorRate) / static_cast<float>(0xFFFF);
cJSON_AddItemToObject(neighbor, KEY_MESSAGEERRORRATE, cJSON_CreateNumber(errRate));
}
return neighbor;
}
static cJSON *MeshRouterNeighbors2Json(const std::vector<otMeshDiagRouterNeighborEntry> &aNeighbors)
{
cJSON *json = cJSON_CreateArray();
for (const otMeshDiagRouterNeighborEntry &neighbor : aNeighbors)
{
cJSON_AddItemToArray(json, MeshRouterNeighborEntry2Json(neighbor));
}
return json;
}
cJSON *CreateMetaCollection(uint32_t aOffset, uint32_t aLimit, uint32_t aTotal)
{
cJSON *meta = cJSON_CreateObject();
cJSON *meta_collection = cJSON_CreateObject();
cJSON_AddNumberToObject(meta_collection, KEY_OFFSET, aOffset);
if (aLimit > 0)
{
cJSON_AddNumberToObject(meta_collection, KEY_LIMIT, aLimit);
}
cJSON_AddNumberToObject(meta_collection, KEY_TOTAL, aTotal);
cJSON_AddItemToObject(meta, KEY_COLLECTION, meta_collection);
return meta;
}
cJSON *CreateMetaCollection(uint32_t aOffset, uint32_t aLimit, uint32_t aTotal, uint32_t aPending)
{
cJSON *meta = cJSON_CreateObject();
cJSON *meta_collection = cJSON_CreateObject();
cJSON_AddNumberToObject(meta_collection, KEY_OFFSET, aOffset);
if (aLimit > 0)
{
cJSON_AddNumberToObject(meta_collection, KEY_LIMIT, aLimit);
}
cJSON_AddNumberToObject(meta_collection, KEY_TOTAL, aTotal);
cJSON_AddItemToObject(meta_collection, KEY_PENDING, cJSON_CreateNumber(aPending));
cJSON_AddItemToObject(meta, KEY_COLLECTION, meta_collection);
return meta;
}
#if OTBR_ENABLE_EPSKC
static const char *EpskcStateToString(otBorderAgentEphemeralKeyState aState)
{
const char *stateStr;
switch (aState)
{
case OT_BORDER_AGENT_STATE_DISABLED:
stateStr = "disabled";
break;
case OT_BORDER_AGENT_STATE_STOPPED:
stateStr = "stopped";
break;
case OT_BORDER_AGENT_STATE_STARTED:
stateStr = "started";
break;
case OT_BORDER_AGENT_STATE_CONNECTED:
stateStr = "connected";
break;
case OT_BORDER_AGENT_STATE_ACCEPTED:
stateStr = "accepted";
break;
default:
stateStr = "unknown";
break;
}
return stateStr;
}
std::string EpskcKeyStatus2JsonString(otBorderAgentEphemeralKeyState aState, uint16_t aPort)
{
std::string ret;
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "state", EpskcStateToString(aState));
cJSON_AddNumberToObject(root, "port", aPort);
ret = Json2String(root);
cJSON_Delete(root);
return ret;
}
std::string EpskcActivateResult2JsonString(const std::string &aTap, uint16_t aPort)
{
std::string ret;
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "tap", aTap.c_str());
cJSON_AddNumberToObject(root, "port", aPort);
ret = Json2String(root);
cJSON_Delete(root);
return ret;
}
bool JsonEpskcActivateParams(const std::string &aJson, uint32_t &aLifetime, uint16_t &aPort)
{
cJSON *root;
cJSON *value;
bool ret = true;
root = cJSON_Parse(aJson.c_str());
VerifyOrExit(root != nullptr, ret = false);
VerifyOrExit(cJSON_IsObject(root), ret = false);
value = cJSON_GetObjectItemCaseSensitive(root, "lifetime");
if (value != nullptr)
{
VerifyOrExit(cJSON_IsNumber(value), ret = false);
VerifyOrExit(value->valuedouble >= 0.0 && value->valuedouble <= UINT32_MAX, ret = false);
aLifetime = static_cast<uint32_t>(value->valuedouble);
}
value = cJSON_GetObjectItemCaseSensitive(root, "port");
if (value != nullptr)
{
VerifyOrExit(cJSON_IsNumber(value), ret = false);
VerifyOrExit(value->valuedouble >= 0.0 && value->valuedouble <= UINT16_MAX, ret = false);
aPort = static_cast<uint16_t>(value->valuedouble);
}
exit:
cJSON_Delete(root);
return ret;
}
#endif // OTBR_ENABLE_EPSKC
} // namespace Json
} // namespace rest
} // namespace otbr