Skip to content

Commit 7f5401f

Browse files
net: rpc: openthread: add networkdiagnostic APIs
Add APIs for getting and resetting network diagnostic TLVs. Signed-off-by: Maciej Baczmanski <maciej.baczmanski@nordicsemi.no>
1 parent 1b0df5c commit 7f5401f

File tree

6 files changed

+924
-4
lines changed

6 files changed

+924
-4
lines changed

doc/nrf/libraries/networking/ot_rpc.rst

+3
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,14 @@ OpenThread RPC currently supports the serialization of the following OpenThread
162162
* :c:func:`otThreadGetMeshLocalPrefix`
163163
* :c:func:`otThreadGetMleCounters`
164164
* :c:func:`otThreadGetNetworkName`
165+
* :c:func:`otThreadGetNextDiagnosticTlv`
165166
* :c:func:`otThreadGetPartitionId`
166167
* :c:func:`otThreadGetVendorName`
167168
* :c:func:`otThreadGetVendorModel`
168169
* :c:func:`otThreadGetVendorSwVersion`
169170
* :c:func:`otThreadGetVersion`
171+
* :c:func:`otThreadSendDiagnosticGet`
172+
* :c:func:`otThreadSendDiagnosticReset`
170173
* :c:func:`otThreadSetEnabled`
171174
* :c:func:`otThreadSetLinkMode`
172175
* :c:func:`otThreadSetVendorName`

samples/nrf_rpc/protocols_serialization/client/src/ot_shell.c

+263-3
Original file line numberDiff line numberDiff line change
@@ -484,16 +484,17 @@ static void handle_udp_receive(void *context, otMessage *message, const otMessag
484484
uint16_t offset;
485485
uint16_t read;
486486
char buf[128] = {0};
487+
const struct shell *sh = (const struct shell *)context;
487488

488489
offset = otMessageGetOffset(message);
489490
length = otMessageGetLength(message);
490491

491492
read = otMessageRead(message, offset, buf, length);
492493

493494
if (read > 0) {
494-
printk("RECEIVED: '%s'\n", buf);
495+
shell_print(sh, "RECEIVED: '%s'", buf);
495496
} else {
496-
printk("message empty\n");
497+
shell_print(sh, "message empty");
497498
}
498499
}
499500

@@ -506,7 +507,7 @@ static int cmd_test_udp_init(const struct shell *sh, size_t argc, char *argv[])
506507

507508
listen_sock_addr.mPort = PORT;
508509

509-
otUdpOpen(NULL, &udp_socket, handle_udp_receive, NULL);
510+
otUdpOpen(NULL, &udp_socket, handle_udp_receive, (void *)sh);
510511
otUdpBind(NULL, &udp_socket, &listen_sock_addr, OT_NETIF_THREAD);
511512

512513
return 0;
@@ -1042,6 +1043,262 @@ static int cmd_test_vendor_data(const struct shell *sh, size_t argc, char *argv[
10421043
return 0;
10431044
}
10441045

1046+
static void handle_receive_diagnostic_get(otError error, otMessage *message,
1047+
const otMessageInfo *message_info, void *context)
1048+
{
1049+
otNetworkDiagTlv diagTlv;
1050+
otNetworkDiagIterator iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT;
1051+
1052+
const struct shell *sh = (const struct shell *)context;
1053+
char addr_string[NET_IPV6_ADDR_LEN];
1054+
1055+
if (error != OT_ERROR_NONE) {
1056+
shell_error(sh, "Failed to get the diagnostic response, error: %d", error);
1057+
return;
1058+
}
1059+
1060+
if (!net_addr_ntop(AF_INET6, message_info->mPeerAddr.mFields.m8,
1061+
addr_string, sizeof(addr_string))) {
1062+
shell_error(sh, "Failed to convert the IPv6 address");
1063+
return;
1064+
}
1065+
1066+
shell_print(sh, "------------------------------------------------------------------");
1067+
shell_print(sh, "Received DIAG_GET.rsp/ans from %s", addr_string);
1068+
1069+
while (otThreadGetNextDiagnosticTlv(message, &iterator, &diagTlv) == OT_ERROR_NONE) {
1070+
shell_fprintf(sh, SHELL_NORMAL, "\nTLV type: 0x%x ", diagTlv.mType);
1071+
switch (diagTlv.mType) {
1072+
case OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS:
1073+
shell_print(sh, "(MAC Extended Address TLV)");
1074+
shell_hexdump(sh, diagTlv.mData.mExtAddress.m8, OT_EXT_ADDRESS_SIZE);
1075+
break;
1076+
case OT_NETWORK_DIAGNOSTIC_TLV_EUI64:
1077+
shell_print(sh, "(EUI64 TLV)");
1078+
shell_hexdump(sh, diagTlv.mData.mEui64.m8, OT_EXT_ADDRESS_SIZE);
1079+
break;
1080+
case OT_NETWORK_DIAGNOSTIC_TLV_MODE:
1081+
shell_print(sh, "(Mode TLV)");
1082+
shell_print(sh, "RX on when idle: %s", diagTlv.mData.mMode.mRxOnWhenIdle ?
1083+
"true" : "false");
1084+
shell_print(sh, "Device type: %s", diagTlv.mData.mMode.mDeviceType ?
1085+
"true" : "false");
1086+
shell_print(sh, "Network data: %s", diagTlv.mData.mMode.mNetworkData ?
1087+
"true" : "false");
1088+
break;
1089+
case OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY:
1090+
shell_print(sh, "(Connectivity TLV)");
1091+
shell_print(sh, "Parent priority: %d",
1092+
diagTlv.mData.mConnectivity.mParentPriority);
1093+
shell_print(sh, "Link quality 3: %u",
1094+
diagTlv.mData.mConnectivity.mLinkQuality3);
1095+
shell_print(sh, "Link quality 2: %u",
1096+
diagTlv.mData.mConnectivity.mLinkQuality2);
1097+
shell_print(sh, "Link quality 1: %u",
1098+
diagTlv.mData.mConnectivity.mLinkQuality1);
1099+
shell_print(sh, "Leader cost: %u",
1100+
diagTlv.mData.mConnectivity.mLeaderCost);
1101+
shell_print(sh, "ID sequence: %u", diagTlv.mData.mConnectivity.mIdSequence);
1102+
shell_print(sh, "Active routers: %u",
1103+
diagTlv.mData.mConnectivity.mActiveRouters);
1104+
shell_print(sh, "SED buffer size: %u",
1105+
diagTlv.mData.mConnectivity.mSedBufferSize);
1106+
shell_print(sh, "SED datagram count: %u",
1107+
diagTlv.mData.mConnectivity.mSedDatagramCount);
1108+
break;
1109+
case OT_NETWORK_DIAGNOSTIC_TLV_ROUTE:
1110+
shell_print(sh, "(Route64 TLV)");
1111+
shell_print(sh, "ID sequence: %u", diagTlv.mData.mRoute.mIdSequence);
1112+
shell_print(sh, "Route count: %u", diagTlv.mData.mRoute.mRouteCount);
1113+
1114+
for (int i = 0; i < diagTlv.mData.mRoute.mRouteCount; i++) {
1115+
shell_print(sh, "\tRouter ID: %u",
1116+
diagTlv.mData.mRoute.mRouteData[i].mRouterId);
1117+
shell_print(sh, "\tLink quality in: %u",
1118+
diagTlv.mData.mRoute.mRouteData[i].mLinkQualityIn);
1119+
shell_print(sh, "\tLink quality out: %u",
1120+
diagTlv.mData.mRoute.mRouteData[i].mLinkQualityOut);
1121+
shell_print(sh, "\tRoute cost: %u\n",
1122+
diagTlv.mData.mRoute.mRouteData[i].mRouteCost);
1123+
}
1124+
break;
1125+
case OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA:
1126+
shell_print(sh, "(Leader Data TLV)");
1127+
shell_print(sh, "Partition ID: 0x%x",
1128+
diagTlv.mData.mLeaderData.mPartitionId);
1129+
shell_print(sh, "Weighting: %u", diagTlv.mData.mLeaderData.mWeighting);
1130+
shell_print(sh, "Data version: %u", diagTlv.mData.mLeaderData.mDataVersion);
1131+
shell_print(sh, "Stable data version: %u",
1132+
diagTlv.mData.mLeaderData.mStableDataVersion);
1133+
shell_print(sh, "Leader router ID: 0x%x",
1134+
diagTlv.mData.mLeaderData.mLeaderRouterId);
1135+
break;
1136+
case OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS:
1137+
shell_print(sh, "(MAC Counters TLV)");
1138+
shell_print(sh, "IfInUnknownProtos: %u",
1139+
diagTlv.mData.mMacCounters.mIfInUnknownProtos);
1140+
shell_print(sh, "IfInErrors: %u", diagTlv.mData.mMacCounters.mIfInErrors);
1141+
shell_print(sh, "IfOutErrors: %u", diagTlv.mData.mMacCounters.mIfOutErrors);
1142+
shell_print(sh, "IfInUcastPkts: %u",
1143+
diagTlv.mData.mMacCounters.mIfInUcastPkts);
1144+
shell_print(sh, "IfInBroadcastPkts: %u",
1145+
diagTlv.mData.mMacCounters.mIfInBroadcastPkts);
1146+
shell_print(sh, "IfInDiscards: %u",
1147+
diagTlv.mData.mMacCounters.mIfInDiscards);
1148+
shell_print(sh, "IfOutUcastPkts: %u",
1149+
diagTlv.mData.mMacCounters.mIfOutUcastPkts);
1150+
shell_print(sh, "IfOutBroadcastPkts: %u",
1151+
diagTlv.mData.mMacCounters.mIfOutBroadcastPkts);
1152+
shell_print(sh, "IfOutDiscards: %u",
1153+
diagTlv.mData.mMacCounters.mIfOutDiscards);
1154+
break;
1155+
case OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS:
1156+
shell_print(sh, "(MLE Counters TLV)");
1157+
shell_print(sh, "DisabledRole: %u",
1158+
diagTlv.mData.mMleCounters.mDisabledRole);
1159+
shell_print(sh, "DetachedRole: %u",
1160+
diagTlv.mData.mMleCounters.mDetachedRole);
1161+
shell_print(sh, "ChildRole: %u", diagTlv.mData.mMleCounters.mChildRole);
1162+
shell_print(sh, "RouterRole: %u", diagTlv.mData.mMleCounters.mRouterRole);
1163+
shell_print(sh, "LeaderRole: %u", diagTlv.mData.mMleCounters.mLeaderRole);
1164+
shell_print(sh, "AttachAttempts: %u",
1165+
diagTlv.mData.mMleCounters.mAttachAttempts);
1166+
shell_print(sh, "PartitionIdChanges: %u",
1167+
diagTlv.mData.mMleCounters.mPartitionIdChanges);
1168+
shell_print(sh, "BetterPartitionAttachAttempts: %u",
1169+
diagTlv.mData.mMleCounters.mBetterPartitionAttachAttempts);
1170+
shell_print(sh, "ParentChanges: %u",
1171+
diagTlv.mData.mMleCounters.mParentChanges);
1172+
shell_print(sh, "TrackedTime: %llu",
1173+
diagTlv.mData.mMleCounters.mTrackedTime);
1174+
shell_print(sh, "DisabledTime: %llu",
1175+
diagTlv.mData.mMleCounters.mDisabledTime);
1176+
shell_print(sh, "DetachedTime: %llu",
1177+
diagTlv.mData.mMleCounters.mDetachedTime);
1178+
shell_print(sh, "ChildTime: %llu", diagTlv.mData.mMleCounters.mChildTime);
1179+
shell_print(sh, "RouterTime: %llu", diagTlv.mData.mMleCounters.mRouterTime);
1180+
shell_print(sh, "LeaderTime: %llu", diagTlv.mData.mMleCounters.mLeaderTime);
1181+
break;
1182+
case OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL:
1183+
shell_print(sh, "(Battery Level TLV)");
1184+
shell_print(sh, "Battery level: %u", diagTlv.mData.mBatteryLevel);
1185+
break;
1186+
case OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT:
1187+
shell_print(sh, "(Timeout TLV)");
1188+
shell_print(sh, "Timeout: %u", diagTlv.mData.mTimeout);
1189+
break;
1190+
case OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT:
1191+
shell_print(sh, "(Max Child Timeout TLV)");
1192+
shell_print(sh, "Max child timeout: %u", diagTlv.mData.mMaxChildTimeout);
1193+
break;
1194+
case OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS:
1195+
shell_print(sh, "(Address16 TLV)");
1196+
shell_print(sh, "Rloc16: 0x%x", diagTlv.mData.mAddr16);
1197+
break;
1198+
case OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE:
1199+
shell_print(sh, "(Supply Voltage TLV)");
1200+
shell_print(sh, "Supply voltage: %u", diagTlv.mData.mSupplyVoltage);
1201+
break;
1202+
case OT_NETWORK_DIAGNOSTIC_TLV_VERSION:
1203+
shell_print(sh, "(Thread Version TLV)");
1204+
shell_print(sh, "Version: %u", diagTlv.mData.mVersion);
1205+
break;
1206+
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_NAME:
1207+
shell_print(sh, "(Vendor Name TLV)");
1208+
shell_print(sh, "Vendor name: %s", diagTlv.mData.mVendorName);
1209+
break;
1210+
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_MODEL:
1211+
shell_print(sh, "(Vendor Model TLV)");
1212+
shell_print(sh, "Vendor model: %s", diagTlv.mData.mVendorModel);
1213+
break;
1214+
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_SW_VERSION:
1215+
shell_print(sh, "(Vendor SW Version TLV)");
1216+
shell_print(sh, "Vendor SW version: %s", diagTlv.mData.mVendorSwVersion);
1217+
break;
1218+
case OT_NETWORK_DIAGNOSTIC_TLV_THREAD_STACK_VERSION:
1219+
shell_print(sh, "(Thread Stack Version TLV)");
1220+
shell_print(sh, "Thread stack version: %s",
1221+
diagTlv.mData.mThreadStackVersion);
1222+
break;
1223+
case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL:
1224+
shell_print(sh, "(Vendor App URL TLV)");
1225+
shell_print(sh, "Vendor app URL: %s", diagTlv.mData.mVendorAppUrl);
1226+
break;
1227+
case OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA:
1228+
shell_print(sh, "(Network Data TLV)");
1229+
shell_hexdump(sh, diagTlv.mData.mNetworkData.m8,
1230+
diagTlv.mData.mNetworkData.mCount);
1231+
break;
1232+
case OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES:
1233+
shell_print(sh, "(Channel Pages TLV)");
1234+
shell_hexdump(sh, diagTlv.mData.mChannelPages.m8,
1235+
diagTlv.mData.mChannelPages.mCount);
1236+
break;
1237+
case OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST:
1238+
shell_print(sh, "(IPv6 Address List TLV)");
1239+
for (int i = 0; i < diagTlv.mData.mIp6AddrList.mCount; i++) {
1240+
shell_hexdump(sh, diagTlv.mData.mIp6AddrList.mList[i].mFields.m8,
1241+
OT_IP6_ADDRESS_SIZE);
1242+
}
1243+
break;
1244+
case OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE:
1245+
shell_print(sh, "(Child Table TLV)");
1246+
for (int i = 0; i < diagTlv.mData.mChildTable.mCount; i++) {
1247+
shell_print(sh, "\tChild ID: %u",
1248+
diagTlv.mData.mChildTable.mTable[i].mChildId);
1249+
shell_print(sh, "\tTimeout: %u",
1250+
diagTlv.mData.mChildTable.mTable[i].mTimeout);
1251+
shell_print(sh, "\tLink quality: %u",
1252+
diagTlv.mData.mChildTable.mTable[i].mLinkQuality);
1253+
shell_print(sh, "\tRX on when idle: %s",
1254+
diagTlv.mData.mChildTable.mTable[i].mMode.mRxOnWhenIdle
1255+
? "true" : "false");
1256+
shell_print(sh, "\tDevice type: %s",
1257+
diagTlv.mData.mChildTable.mTable[i].mMode.mDeviceType ?
1258+
"true" : "false");
1259+
shell_print(sh, "\tNetwork data: %s",
1260+
diagTlv.mData.mChildTable.mTable[i].mMode.mNetworkData ?
1261+
"true" : "false");
1262+
}
1263+
break;
1264+
1265+
default:
1266+
shell_print(sh, "(Unknown TLV)");
1267+
}
1268+
}
1269+
}
1270+
1271+
static int cmd_test_net_diag(const struct shell *sh, size_t argc, char *argv[])
1272+
{
1273+
uint8_t tlv_types[35];
1274+
uint8_t count = 0;
1275+
otIp6Address addr;
1276+
1277+
if (net_addr_pton(AF_INET6, argv[2], addr.mFields.m8)) {
1278+
shell_error(sh, "Failed to parse IPv6 address: %s", argv[1]);
1279+
return -EINVAL;
1280+
}
1281+
1282+
for (int arg = 3; arg < argc; ++arg) {
1283+
tlv_types[count] = shell_strtoul(argv[arg], 0, NULL);
1284+
count++;
1285+
}
1286+
1287+
if (strcmp(argv[1], "get") == 0) {
1288+
otThreadSendDiagnosticGet(NULL, &addr, tlv_types, count,
1289+
handle_receive_diagnostic_get, (void *)sh);
1290+
1291+
} else if (strcmp(argv[1], "reset") == 0) {
1292+
otThreadSendDiagnosticReset(NULL, &addr, tlv_types, count);
1293+
1294+
} else {
1295+
shell_error(sh, "Invalid argument %s", argv[1]);
1296+
return -EINVAL;
1297+
}
1298+
1299+
return 0;
1300+
}
1301+
10451302
static void print_txt_entry(const struct shell *sh, const otDnsTxtEntry *entry)
10461303
{
10471304
char buffer[128];
@@ -1592,6 +1849,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
15921849
SHELL_CMD_ARG(test_vendor_data, NULL, "Vendor data, args: <vendor-name> <vendor-model>"
15931850
" <vendor-sw-version>",
15941851
cmd_test_vendor_data, 4, 0),
1852+
SHELL_CMD_ARG(test_net_diag, NULL, "Network diag, args: <get|reset> <IPv6-address>"
1853+
" <tlv-type ...>",
1854+
cmd_test_net_diag, 4, 255),
15951855
SHELL_SUBCMD_SET_END);
15961856

15971857
SHELL_CMD_ARG_REGISTER(ot, &ot_cmds,

0 commit comments

Comments
 (0)