xref: /aosp_15_r20/external/ot-br-posix/src/android/otdaemon_telemetry.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *    Copyright (c) 2023, The OpenThread Authors.
3  *    All rights reserved.
4  *
5  *    Redistribution and use in source and binary forms, with or without
6  *    modification, are permitted provided that the following conditions are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *    3. Neither the name of the copyright holder nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *    POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include "android/otdaemon_telemetry.hpp"
29 
30 #include <openthread/border_agent.h>
31 #include <openthread/nat64.h>
32 #include <openthread/openthread-system.h>
33 #include <openthread/thread.h>
34 #include <openthread/thread_ftd.h>
35 #include <openthread/trel.h>
36 #include <openthread/platform/radio.h>
37 
38 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
39 #include <openthread/dnssd_server.h>
40 #endif
41 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
42 #include <openthread/srp_server.h>
43 #endif
44 
45 #include "statslog_threadnetwork.h"
46 #include "common/code_utils.hpp"
47 #include "mdns/mdns.hpp"
48 #include "proto/threadnetwork_atoms.pb.h"
49 
50 namespace otbr {
51 namespace Android {
52 using android::os::statsd::threadnetwork::ThreadnetworkDeviceInfoReported;
53 using android::os::statsd::threadnetwork::ThreadnetworkTelemetryDataReported;
54 using android::os::statsd::threadnetwork::ThreadnetworkTopoEntryRepeated;
55 using TelemetryData = android::os::statsd::threadnetwork::ThreadnetworkTelemetryDataReported;
56 
TelemetryNodeTypeFromRoleAndLinkMode(const otDeviceRole & aRole,const otLinkModeConfig & aLinkModeCfg)57 static uint32_t TelemetryNodeTypeFromRoleAndLinkMode(const otDeviceRole &aRole, const otLinkModeConfig &aLinkModeCfg)
58 {
59     uint32_t nodeType;
60 
61     switch (aRole)
62     {
63     case OT_DEVICE_ROLE_DISABLED:
64         nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_DISABLED;
65         break;
66     case OT_DEVICE_ROLE_DETACHED:
67         nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_DETACHED;
68         break;
69     case OT_DEVICE_ROLE_ROUTER:
70         nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_ROUTER;
71         break;
72     case OT_DEVICE_ROLE_LEADER:
73         nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_LEADER;
74         break;
75     case OT_DEVICE_ROLE_CHILD:
76         if (!aLinkModeCfg.mRxOnWhenIdle)
77         {
78             nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_SLEEPY_END;
79         }
80         else if (!aLinkModeCfg.mDeviceType)
81         {
82             // If it's not an FTD, return as minimal end device.
83             nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_MINIMAL_END;
84         }
85         else
86         {
87             nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_END;
88         }
89         break;
90     default:
91         nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_UNSPECIFIED;
92     }
93 
94     return nodeType;
95 }
96 
97 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
SrpServerStateFromOtSrpServerState(otSrpServerState aSrpServerState)98 ThreadnetworkTelemetryDataReported::SrpServerState SrpServerStateFromOtSrpServerState(otSrpServerState aSrpServerState)
99 {
100     ThreadnetworkTelemetryDataReported::SrpServerState srpServerState;
101 
102     switch (aSrpServerState)
103     {
104     case OT_SRP_SERVER_STATE_DISABLED:
105         srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_DISABLED;
106         break;
107     case OT_SRP_SERVER_STATE_RUNNING:
108         srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_RUNNING;
109         break;
110     case OT_SRP_SERVER_STATE_STOPPED:
111         srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_STOPPED;
112         break;
113     default:
114         srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_UNSPECIFIED;
115     }
116     return srpServerState;
117 }
118 
SrpServerAddressModeFromOtSrpServerAddressMode(otSrpServerAddressMode aSrpServerAddressMode)119 ThreadnetworkTelemetryDataReported::SrpServerAddressMode SrpServerAddressModeFromOtSrpServerAddressMode(
120     otSrpServerAddressMode aSrpServerAddressMode)
121 {
122     ThreadnetworkTelemetryDataReported::SrpServerAddressMode srpServerAddressMode;
123 
124     switch (aSrpServerAddressMode)
125     {
126     case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST:
127         srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_STATE_ANYCAST;
128         break;
129     case OT_SRP_SERVER_ADDRESS_MODE_UNICAST:
130         srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_UNICAST;
131         break;
132     default:
133         srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_UNSPECIFIED;
134     }
135     return srpServerAddressMode;
136 }
137 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
138 
CopyMdnsResponseCounters(const MdnsResponseCounters & from,ThreadnetworkTelemetryDataReported::MdnsResponseCounters * to)139 void CopyMdnsResponseCounters(const MdnsResponseCounters                               &from,
140                               ThreadnetworkTelemetryDataReported::MdnsResponseCounters *to)
141 {
142     to->set_success_count(from.mSuccess);
143     to->set_not_found_count(from.mNotFound);
144     to->set_invalid_args_count(from.mInvalidArgs);
145     to->set_duplicated_count(from.mDuplicated);
146     to->set_not_implemented_count(from.mNotImplemented);
147     to->set_unknown_error_count(from.mUnknownError);
148     to->set_aborted_count(from.mAborted);
149     to->set_invalid_state_count(from.mInvalidState);
150 }
151 
Nat64StateFromOtNat64State(otNat64State aNat64State)152 TelemetryData::Nat64State Nat64StateFromOtNat64State(otNat64State aNat64State)
153 {
154     TelemetryData::Nat64State nat64State;
155 
156     switch (aNat64State)
157     {
158     case OT_NAT64_STATE_DISABLED:
159         nat64State = TelemetryData::NAT64_STATE_DISABLED;
160         break;
161     case OT_NAT64_STATE_NOT_RUNNING:
162         nat64State = TelemetryData::NAT64_STATE_NOT_RUNNING;
163         break;
164     case OT_NAT64_STATE_IDLE:
165         nat64State = TelemetryData::NAT64_STATE_IDLE;
166         break;
167     case OT_NAT64_STATE_ACTIVE:
168         nat64State = TelemetryData::NAT64_STATE_ACTIVE;
169         break;
170     default:
171         nat64State = TelemetryData::NAT64_STATE_UNSPECIFIED;
172     }
173 
174     return nat64State;
175 }
176 
RetrieveNat64State(otInstance * aInstance,TelemetryData::WpanBorderRouter * aWpanBorderRouter)177 void RetrieveNat64State(otInstance *aInstance, TelemetryData::WpanBorderRouter *aWpanBorderRouter)
178 {
179     auto nat64State = aWpanBorderRouter->mutable_nat64_state();
180 
181     nat64State->set_prefix_manager_state(Nat64StateFromOtNat64State(otNat64GetPrefixManagerState(aInstance)));
182     nat64State->set_translator_state(Nat64StateFromOtNat64State(otNat64GetTranslatorState(aInstance)));
183 }
184 
RetrieveNat64Counters(otInstance * aInstance,TelemetryData::BorderRoutingCounters * aBorderRoutingCounters)185 void RetrieveNat64Counters(otInstance *aInstance, TelemetryData::BorderRoutingCounters *aBorderRoutingCounters)
186 {
187     {
188         auto nat64IcmpCounters = aBorderRoutingCounters->mutable_nat64_protocol_counters()->mutable_icmp();
189         auto nat64UdpCounters  = aBorderRoutingCounters->mutable_nat64_protocol_counters()->mutable_udp();
190         auto nat64TcpCounters  = aBorderRoutingCounters->mutable_nat64_protocol_counters()->mutable_tcp();
191         otNat64ProtocolCounters otCounters;
192 
193         otNat64GetCounters(aInstance, &otCounters);
194         nat64IcmpCounters->set_ipv4_to_ipv6_packets(otCounters.mIcmp.m4To6Packets);
195         nat64IcmpCounters->set_ipv4_to_ipv6_bytes(otCounters.mIcmp.m4To6Bytes);
196         nat64IcmpCounters->set_ipv6_to_ipv4_packets(otCounters.mIcmp.m6To4Packets);
197         nat64IcmpCounters->set_ipv6_to_ipv4_bytes(otCounters.mIcmp.m6To4Bytes);
198         nat64UdpCounters->set_ipv4_to_ipv6_packets(otCounters.mUdp.m4To6Packets);
199         nat64UdpCounters->set_ipv4_to_ipv6_bytes(otCounters.mUdp.m4To6Bytes);
200         nat64UdpCounters->set_ipv6_to_ipv4_packets(otCounters.mUdp.m6To4Packets);
201         nat64UdpCounters->set_ipv6_to_ipv4_bytes(otCounters.mUdp.m6To4Bytes);
202         nat64TcpCounters->set_ipv4_to_ipv6_packets(otCounters.mTcp.m4To6Packets);
203         nat64TcpCounters->set_ipv4_to_ipv6_bytes(otCounters.mTcp.m4To6Bytes);
204         nat64TcpCounters->set_ipv6_to_ipv4_packets(otCounters.mTcp.m6To4Packets);
205         nat64TcpCounters->set_ipv6_to_ipv4_bytes(otCounters.mTcp.m6To4Bytes);
206     }
207 
208     {
209         auto                 errorCounters = aBorderRoutingCounters->mutable_nat64_error_counters();
210         otNat64ErrorCounters otCounters;
211         otNat64GetErrorCounters(aInstance, &otCounters);
212 
213         errorCounters->mutable_unknown()->set_ipv4_to_ipv6_packets(otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNKNOWN]);
214         errorCounters->mutable_unknown()->set_ipv6_to_ipv4_packets(otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNKNOWN]);
215         errorCounters->mutable_illegal_packet()->set_ipv4_to_ipv6_packets(
216             otCounters.mCount4To6[OT_NAT64_DROP_REASON_ILLEGAL_PACKET]);
217         errorCounters->mutable_illegal_packet()->set_ipv6_to_ipv4_packets(
218             otCounters.mCount6To4[OT_NAT64_DROP_REASON_ILLEGAL_PACKET]);
219         errorCounters->mutable_unsupported_protocol()->set_ipv4_to_ipv6_packets(
220             otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO]);
221         errorCounters->mutable_unsupported_protocol()->set_ipv6_to_ipv4_packets(
222             otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO]);
223         errorCounters->mutable_no_mapping()->set_ipv4_to_ipv6_packets(
224             otCounters.mCount4To6[OT_NAT64_DROP_REASON_NO_MAPPING]);
225         errorCounters->mutable_no_mapping()->set_ipv6_to_ipv4_packets(
226             otCounters.mCount6To4[OT_NAT64_DROP_REASON_NO_MAPPING]);
227     }
228 }
229 
RetrieveBorderAgentInfo(otInstance * aInstance,TelemetryData::BorderAgentInfo * aBorderAgentInfo)230 void RetrieveBorderAgentInfo(otInstance *aInstance, TelemetryData::BorderAgentInfo *aBorderAgentInfo)
231 {
232     auto baCounters            = aBorderAgentInfo->mutable_border_agent_counters();
233     auto otBorderAgentCounters = *otBorderAgentGetCounters(aInstance);
234 
235     baCounters->set_epskc_activations(otBorderAgentCounters.mEpskcActivations);
236     baCounters->set_epskc_deactivation_clears(otBorderAgentCounters.mEpskcDeactivationClears);
237     baCounters->set_epskc_deactivation_timeouts(otBorderAgentCounters.mEpskcDeactivationTimeouts);
238     baCounters->set_epskc_deactivation_max_attempts(otBorderAgentCounters.mEpskcDeactivationMaxAttempts);
239     baCounters->set_epskc_deactivation_disconnects(otBorderAgentCounters.mEpskcDeactivationDisconnects);
240     baCounters->set_epskc_invalid_ba_state_errors(otBorderAgentCounters.mEpskcInvalidBaStateErrors);
241     baCounters->set_epskc_invalid_args_errors(otBorderAgentCounters.mEpskcInvalidArgsErrors);
242     baCounters->set_epskc_start_secure_session_errors(otBorderAgentCounters.mEpskcStartSecureSessionErrors);
243     baCounters->set_epskc_secure_session_successes(otBorderAgentCounters.mEpskcSecureSessionSuccesses);
244     baCounters->set_epskc_secure_session_failures(otBorderAgentCounters.mEpskcSecureSessionFailures);
245     baCounters->set_epskc_commissioner_petitions(otBorderAgentCounters.mEpskcCommissionerPetitions);
246 
247     baCounters->set_pskc_secure_session_successes(otBorderAgentCounters.mPskcSecureSessionSuccesses);
248     baCounters->set_pskc_secure_session_failures(otBorderAgentCounters.mPskcSecureSessionFailures);
249     baCounters->set_pskc_commissioner_petitions(otBorderAgentCounters.mPskcCommissionerPetitions);
250 
251     baCounters->set_mgmt_active_get_reqs(otBorderAgentCounters.mMgmtActiveGets);
252     baCounters->set_mgmt_pending_get_reqs(otBorderAgentCounters.mMgmtPendingGets);
253 }
254 
RetrieveTrelInfo(otInstance * aInstance,TelemetryData::TrelInfo * aTrelInfo)255 void RetrieveTrelInfo(otInstance *aInstance, TelemetryData::TrelInfo *aTrelInfo)
256 {
257     auto otTrelCounters = otTrelGetCounters(aInstance);
258     auto trelCounters   = aTrelInfo->mutable_counters();
259 
260     aTrelInfo->set_is_trel_enabled(otTrelIsEnabled(aInstance));
261     aTrelInfo->set_num_trel_peers(otTrelGetNumberOfPeers(aInstance));
262 
263     trelCounters->set_trel_tx_packets(otTrelCounters->mTxPackets);
264     trelCounters->set_trel_tx_bytes(otTrelCounters->mTxBytes);
265     trelCounters->set_trel_tx_packets_failed(otTrelCounters->mTxFailure);
266     trelCounters->set_trel_rx_packets(otTrelCounters->mRxPackets);
267     trelCounters->set_trel_rx_bytes(otTrelCounters->mRxBytes);
268 }
269 
RetrieveTelemetryAtom(otInstance * otInstance,Mdns::Publisher * aPublisher,ThreadnetworkTelemetryDataReported & telemetryDataReported,ThreadnetworkTopoEntryRepeated & topoEntryRepeated,ThreadnetworkDeviceInfoReported & deviceInfoReported)270 otError RetrieveTelemetryAtom(otInstance                         *otInstance,
271                               Mdns::Publisher                    *aPublisher,
272                               ThreadnetworkTelemetryDataReported &telemetryDataReported,
273                               ThreadnetworkTopoEntryRepeated     &topoEntryRepeated,
274                               ThreadnetworkDeviceInfoReported    &deviceInfoReported)
275 {
276     otError                     error = OT_ERROR_NONE;
277     std::vector<otNeighborInfo> neighborTable;
278 
279     // Begin of ThreadnetworkDeviceInfoReported section.
280     deviceInfoReported.set_thread_version(otThreadGetVersion());
281     deviceInfoReported.set_ot_rcp_version(otGetRadioVersionString(otInstance));
282     // TODO: populate ot_host_version, thread_daemon_version.
283     // End of ThreadnetworkDeviceInfoReported section.
284 
285     // Begin of WpanStats section.
286     auto wpanStats = telemetryDataReported.mutable_wpan_stats();
287 
288     {
289         otDeviceRole     role  = otThreadGetDeviceRole(otInstance);
290         otLinkModeConfig otCfg = otThreadGetLinkMode(otInstance);
291 
292         wpanStats->set_node_type(TelemetryNodeTypeFromRoleAndLinkMode(role, otCfg));
293     }
294 
295     // Disable telemetry retrieval when Thread stack is disabled. DeviceInfo section above is
296     // always uploaded to understand the device count.
297     if (wpanStats->node_type() == ThreadnetworkTelemetryDataReported::NODE_TYPE_DISABLED)
298     {
299         otbrLogDebug("Skip telemetry retrieval since Thread stack is disabled.");
300         // Return error that only partial telemetries are populated.
301         // TODO: refine the error code name to mean: partial data are populated.
302         return OT_ERROR_FAILED;
303     }
304 
305     wpanStats->set_channel(otLinkGetChannel(otInstance));
306 
307     {
308         uint16_t ccaFailureRate = otLinkGetCcaFailureRate(otInstance);
309 
310         wpanStats->set_mac_cca_fail_rate(static_cast<float>(ccaFailureRate) / 0xffff);
311     }
312 
313     {
314         int8_t radioTxPower;
315 
316         if (otPlatRadioGetTransmitPower(otInstance, &radioTxPower) == OT_ERROR_NONE)
317         {
318             wpanStats->set_radio_tx_power(radioTxPower);
319         }
320         else
321         {
322             error = OT_ERROR_FAILED;
323         }
324     }
325 
326     {
327         const otMacCounters *linkCounters = otLinkGetCounters(otInstance);
328 
329         wpanStats->set_phy_rx(linkCounters->mRxTotal);
330         wpanStats->set_phy_tx(linkCounters->mTxTotal);
331         wpanStats->set_mac_unicast_rx(linkCounters->mRxUnicast);
332         wpanStats->set_mac_unicast_tx(linkCounters->mTxUnicast);
333         wpanStats->set_mac_broadcast_rx(linkCounters->mRxBroadcast);
334         wpanStats->set_mac_broadcast_tx(linkCounters->mTxBroadcast);
335         wpanStats->set_mac_tx_ack_req(linkCounters->mTxAckRequested);
336         wpanStats->set_mac_tx_no_ack_req(linkCounters->mTxNoAckRequested);
337         wpanStats->set_mac_tx_acked(linkCounters->mTxAcked);
338         wpanStats->set_mac_tx_data(linkCounters->mTxData);
339         wpanStats->set_mac_tx_data_poll(linkCounters->mTxDataPoll);
340         wpanStats->set_mac_tx_beacon(linkCounters->mTxBeacon);
341         wpanStats->set_mac_tx_beacon_req(linkCounters->mTxBeaconRequest);
342         wpanStats->set_mac_tx_other_pkt(linkCounters->mTxOther);
343         wpanStats->set_mac_tx_retry(linkCounters->mTxRetry);
344         wpanStats->set_mac_rx_data(linkCounters->mRxData);
345         wpanStats->set_mac_rx_data_poll(linkCounters->mRxDataPoll);
346         wpanStats->set_mac_rx_beacon(linkCounters->mRxBeacon);
347         wpanStats->set_mac_rx_beacon_req(linkCounters->mRxBeaconRequest);
348         wpanStats->set_mac_rx_other_pkt(linkCounters->mRxOther);
349         wpanStats->set_mac_rx_filter_whitelist(linkCounters->mRxAddressFiltered);
350         wpanStats->set_mac_rx_filter_dest_addr(linkCounters->mRxDestAddrFiltered);
351         wpanStats->set_mac_tx_fail_cca(linkCounters->mTxErrCca);
352         wpanStats->set_mac_rx_fail_decrypt(linkCounters->mRxErrSec);
353         wpanStats->set_mac_rx_fail_no_frame(linkCounters->mRxErrNoFrame);
354         wpanStats->set_mac_rx_fail_unknown_neighbor(linkCounters->mRxErrUnknownNeighbor);
355         wpanStats->set_mac_rx_fail_invalid_src_addr(linkCounters->mRxErrInvalidSrcAddr);
356         wpanStats->set_mac_rx_fail_fcs(linkCounters->mRxErrFcs);
357         wpanStats->set_mac_rx_fail_other(linkCounters->mRxErrOther);
358     }
359 
360     {
361         const otIpCounters *ipCounters = otThreadGetIp6Counters(otInstance);
362 
363         wpanStats->set_ip_tx_success(ipCounters->mTxSuccess);
364         wpanStats->set_ip_rx_success(ipCounters->mRxSuccess);
365         wpanStats->set_ip_tx_failure(ipCounters->mTxFailure);
366         wpanStats->set_ip_rx_failure(ipCounters->mRxFailure);
367     }
368     // End of WpanStats section.
369 
370     {
371         // Begin of WpanTopoFull section.
372         auto     wpanTopoFull = telemetryDataReported.mutable_wpan_topo_full();
373         uint16_t rloc16       = otThreadGetRloc16(otInstance);
374 
375         wpanTopoFull->set_rloc16(rloc16);
376 
377         {
378             otRouterInfo info;
379 
380             if (otThreadGetRouterInfo(otInstance, rloc16, &info) == OT_ERROR_NONE)
381             {
382                 wpanTopoFull->set_router_id(info.mRouterId);
383             }
384             else
385             {
386                 error = OT_ERROR_FAILED;
387             }
388         }
389 
390         {
391             otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT;
392             otNeighborInfo         neighborInfo;
393 
394             while (otThreadGetNextNeighborInfo(otInstance, &iter, &neighborInfo) == OT_ERROR_NONE)
395             {
396                 neighborTable.push_back(neighborInfo);
397             }
398         }
399         wpanTopoFull->set_neighbor_table_size(neighborTable.size());
400 
401         uint16_t                 childIndex = 0;
402         otChildInfo              childInfo;
403         std::vector<otChildInfo> childTable;
404 
405         while (otThreadGetChildInfoByIndex(otInstance, childIndex, &childInfo) == OT_ERROR_NONE)
406         {
407             childTable.push_back(childInfo);
408             childIndex++;
409         }
410         wpanTopoFull->set_child_table_size(childTable.size());
411 
412         {
413             struct otLeaderData leaderData;
414 
415             if (otThreadGetLeaderData(otInstance, &leaderData) == OT_ERROR_NONE)
416             {
417                 wpanTopoFull->set_leader_router_id(leaderData.mLeaderRouterId);
418                 wpanTopoFull->set_leader_weight(leaderData.mWeighting);
419                 // Do not log network_data_version.
420             }
421             else
422             {
423                 error = OT_ERROR_FAILED;
424             }
425         }
426 
427         uint8_t weight = otThreadGetLocalLeaderWeight(otInstance);
428 
429         wpanTopoFull->set_leader_local_weight(weight);
430 
431         int8_t rssi = otPlatRadioGetRssi(otInstance);
432 
433         wpanTopoFull->set_instant_rssi(rssi);
434 
435         const otExtendedPanId *extPanId = otThreadGetExtendedPanId(otInstance);
436         uint64_t               extPanIdVal;
437 
438         extPanIdVal = ConvertOpenThreadUint64(extPanId->m8);
439         wpanTopoFull->set_has_extended_pan_id(extPanIdVal != 0);
440         // Note: Used leader_router_id instead of leader_rloc16.
441         // Note: Network level info (e.g., extended_pan_id, partition_id, is_active_br) is not logged.
442         // TODO: populate is_active_srp_server, sum_on_link_prefix_changes, preferred_router_id
443         // if needed.
444         // End of WpanTopoFull section.
445 
446         // Begin of TopoEntry section.
447         std::map<uint16_t, const otChildInfo *> childMap;
448 
449         for (const otChildInfo &childInfo : childTable)
450         {
451             auto pair = childMap.insert({childInfo.mRloc16, &childInfo});
452             if (!pair.second)
453             {
454                 // This shouldn't happen, so log an error. It doesn't matter which
455                 // duplicate is kept.
456                 otbrLogErr("Children with duplicate RLOC16 found: 0x%04x", static_cast<int>(childInfo.mRloc16));
457             }
458         }
459 
460         for (const otNeighborInfo &neighborInfo : neighborTable)
461         {
462             auto topoEntry = topoEntryRepeated.mutable_topo_entry_repeated()->add_topo_entries();
463 
464             // 0~15: uint16_t rloc_16
465             // 16~31: uint16_t version Thread version of the neighbor
466             uint32_t comboTelemetry1 = 0;
467             comboTelemetry1 |= (((uint32_t)neighborInfo.mRloc16) & 0x0000FFFF);
468             comboTelemetry1 |= ((((uint32_t)neighborInfo.mVersion) & 0x0000FFFF) << 16);
469             topoEntry->set_combo_telemetry1(comboTelemetry1);
470 
471             topoEntry->set_age_sec(neighborInfo.mAge);
472 
473             // 0~7: uint8_t link_quality_in
474             // 8~15: int8_t average_rssi
475             // 16~23: int8_t last_rssi
476             // 24~31: uint8_t network_data_version
477             uint32_t comboTelemetry2 = 0;
478             comboTelemetry2 |= (((uint32_t)neighborInfo.mLinkQualityIn) & 0x000000FF);
479             comboTelemetry2 |= ((((uint32_t)neighborInfo.mAverageRssi) & 0x000000FF) << 8);
480             comboTelemetry2 |= ((((uint32_t)neighborInfo.mLastRssi) & 0x000000FF) << 16);
481             // network_data_version is populated in the next section.
482             topoEntry->set_combo_telemetry2(comboTelemetry2);
483 
484             // Each bit on the flag represents a bool flag
485             // 0: rx_on_when_idle
486             // 1: full_function
487             // 2: secure_data_request
488             // 3: full_network_data
489             // 4: is_child
490             uint32_t topoEntryFlags = 0;
491             topoEntryFlags |= (neighborInfo.mRxOnWhenIdle ? 1 : 0);
492             topoEntryFlags |= ((neighborInfo.mFullThreadDevice ? 1 : 0) << 1);
493             topoEntryFlags |= ((/* secure_data_request */ true ? 1 : 0) << 2);
494             topoEntryFlags |= ((neighborInfo.mFullNetworkData ? 1 : 0) << 3);
495             topoEntry->set_topo_entry_flags(topoEntryFlags);
496 
497             topoEntry->set_link_frame_counter(neighborInfo.mLinkFrameCounter);
498             topoEntry->set_mle_frame_counter(neighborInfo.mMleFrameCounter);
499 
500             // 0~15: uint16_t mac_frame_error_rate. Frame error rate (0xffff->100%). Requires error tracking feature.
501             // 16~31: uint16_t ip_message_error_rate. (IPv6) msg error rate (0xffff->100%). Requires error tracking
502             // feature.
503             uint32_t comboTelemetry3 = 0;
504             comboTelemetry3 |= ((uint32_t)(neighborInfo.mFrameErrorRate) & 0x0000FFFF);
505             comboTelemetry3 |= ((((uint32_t)neighborInfo.mMessageErrorRate) & 0x0000FFFF) << 16);
506             topoEntry->set_combo_telemetry3(comboTelemetry3);
507 
508             if (!neighborInfo.mIsChild)
509             {
510                 continue;
511             }
512 
513             auto it = childMap.find(neighborInfo.mRloc16);
514             if (it == childMap.end())
515             {
516                 otbrLogErr("Neighbor 0x%04x not found in child table", static_cast<int>(neighborInfo.mRloc16));
517                 continue;
518             }
519             const otChildInfo *childInfo = it->second;
520 
521             comboTelemetry2 |= ((((uint32_t)childInfo->mNetworkDataVersion) & 0x000000FF) << 24);
522             topoEntry->set_combo_telemetry2(comboTelemetry2);
523 
524             topoEntryFlags |= ((/* is_child */ true ? 1 : 0) << 4);
525             topoEntry->set_topo_entry_flags(topoEntryFlags);
526 
527             topoEntry->set_timeout_sec(childInfo->mTimeout);
528         }
529         // End of TopoEntry section.
530     }
531 
532     {
533         // Begin of WpanBorderRouter section.
534         auto wpanBorderRouter = telemetryDataReported.mutable_wpan_border_router();
535 
536         // Begin of BorderRoutingCounters section.
537         {
538             auto                           borderRoutingCouters = wpanBorderRouter->mutable_border_routing_counters();
539             const otBorderRoutingCounters *otBorderRoutingCounters = otIp6GetBorderRoutingCounters(otInstance);
540 
541             borderRoutingCouters->mutable_inbound_unicast()->set_packet_count(
542                 otBorderRoutingCounters->mInboundUnicast.mPackets);
543             borderRoutingCouters->mutable_inbound_unicast()->set_byte_count(
544                 otBorderRoutingCounters->mInboundUnicast.mBytes);
545             borderRoutingCouters->mutable_inbound_multicast()->set_packet_count(
546                 otBorderRoutingCounters->mInboundMulticast.mPackets);
547             borderRoutingCouters->mutable_inbound_multicast()->set_byte_count(
548                 otBorderRoutingCounters->mInboundMulticast.mBytes);
549             borderRoutingCouters->mutable_outbound_unicast()->set_packet_count(
550                 otBorderRoutingCounters->mOutboundUnicast.mPackets);
551             borderRoutingCouters->mutable_outbound_unicast()->set_byte_count(
552                 otBorderRoutingCounters->mOutboundUnicast.mBytes);
553             borderRoutingCouters->mutable_outbound_multicast()->set_packet_count(
554                 otBorderRoutingCounters->mOutboundMulticast.mPackets);
555             borderRoutingCouters->mutable_outbound_multicast()->set_byte_count(
556                 otBorderRoutingCounters->mOutboundMulticast.mBytes);
557             borderRoutingCouters->set_ra_rx(otBorderRoutingCounters->mRaRx);
558             borderRoutingCouters->set_ra_tx_success(otBorderRoutingCounters->mRaTxSuccess);
559             borderRoutingCouters->set_ra_tx_failure(otBorderRoutingCounters->mRaTxFailure);
560             borderRoutingCouters->set_rs_rx(otBorderRoutingCounters->mRsRx);
561             borderRoutingCouters->set_rs_tx_success(otBorderRoutingCounters->mRsTxSuccess);
562             borderRoutingCouters->set_rs_tx_failure(otBorderRoutingCounters->mRsTxFailure);
563 
564             RetrieveNat64Counters(otInstance, borderRoutingCouters);
565         }
566 
567         // End of BorderRoutingCounters section.
568 
569 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
570         // Begin of SrpServerInfo section.
571         {
572             auto                               srpServer = wpanBorderRouter->mutable_srp_server();
573             otSrpServerLeaseInfo               leaseInfo;
574             const otSrpServerHost             *host             = nullptr;
575             const otSrpServerResponseCounters *responseCounters = otSrpServerGetResponseCounters(otInstance);
576 
577             srpServer->set_state(SrpServerStateFromOtSrpServerState(otSrpServerGetState(otInstance)));
578             srpServer->set_port(otSrpServerGetPort(otInstance));
579             srpServer->set_address_mode(
580                 SrpServerAddressModeFromOtSrpServerAddressMode(otSrpServerGetAddressMode(otInstance)));
581 
582             auto srpServerHosts            = srpServer->mutable_hosts();
583             auto srpServerServices         = srpServer->mutable_services();
584             auto srpServerResponseCounters = srpServer->mutable_response_counters();
585 
586             while ((host = otSrpServerGetNextHost(otInstance, host)))
587             {
588                 const otSrpServerService *service = nullptr;
589 
590                 if (otSrpServerHostIsDeleted(host))
591                 {
592                     srpServerHosts->set_deleted_count(srpServerHosts->deleted_count() + 1);
593                 }
594                 else
595                 {
596                     srpServerHosts->set_fresh_count(srpServerHosts->fresh_count() + 1);
597                     otSrpServerHostGetLeaseInfo(host, &leaseInfo);
598                     srpServerHosts->set_lease_time_total_ms(srpServerHosts->lease_time_total_ms() + leaseInfo.mLease);
599                     srpServerHosts->set_key_lease_time_total_ms(srpServerHosts->key_lease_time_total_ms() +
600                                                                 leaseInfo.mKeyLease);
601                     srpServerHosts->set_remaining_lease_time_total_ms(srpServerHosts->remaining_lease_time_total_ms() +
602                                                                       leaseInfo.mRemainingLease);
603                     srpServerHosts->set_remaining_key_lease_time_total_ms(
604                         srpServerHosts->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease);
605                 }
606 
607                 while ((service = otSrpServerHostGetNextService(host, service)))
608                 {
609                     if (otSrpServerServiceIsDeleted(service))
610                     {
611                         srpServerServices->set_deleted_count(srpServerServices->deleted_count() + 1);
612                     }
613                     else
614                     {
615                         srpServerServices->set_fresh_count(srpServerServices->fresh_count() + 1);
616                         otSrpServerServiceGetLeaseInfo(service, &leaseInfo);
617                         srpServerServices->set_lease_time_total_ms(srpServerServices->lease_time_total_ms() +
618                                                                    leaseInfo.mLease);
619                         srpServerServices->set_key_lease_time_total_ms(srpServerServices->key_lease_time_total_ms() +
620                                                                        leaseInfo.mKeyLease);
621                         srpServerServices->set_remaining_lease_time_total_ms(
622                             srpServerServices->remaining_lease_time_total_ms() + leaseInfo.mRemainingLease);
623                         srpServerServices->set_remaining_key_lease_time_total_ms(
624                             srpServerServices->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease);
625                     }
626                 }
627             }
628 
629             srpServerResponseCounters->set_success_count(responseCounters->mSuccess);
630             srpServerResponseCounters->set_server_failure_count(responseCounters->mServerFailure);
631             srpServerResponseCounters->set_format_error_count(responseCounters->mFormatError);
632             srpServerResponseCounters->set_name_exists_count(responseCounters->mNameExists);
633             srpServerResponseCounters->set_refused_count(responseCounters->mRefused);
634             srpServerResponseCounters->set_other_count(responseCounters->mOther);
635         }
636         // End of SrpServerInfo section.
637 #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY
638 
639 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
640         // Begin of DnsServerInfo section.
641         {
642             auto            dnsServer                 = wpanBorderRouter->mutable_dns_server();
643             auto            dnsServerResponseCounters = dnsServer->mutable_response_counters();
644             otDnssdCounters otDnssdCounters           = *otDnssdGetCounters(otInstance);
645 
646             dnsServerResponseCounters->set_success_count(otDnssdCounters.mSuccessResponse);
647             dnsServerResponseCounters->set_server_failure_count(otDnssdCounters.mServerFailureResponse);
648             dnsServerResponseCounters->set_format_error_count(otDnssdCounters.mFormatErrorResponse);
649             dnsServerResponseCounters->set_name_error_count(otDnssdCounters.mNameErrorResponse);
650             dnsServerResponseCounters->set_not_implemented_count(otDnssdCounters.mNotImplementedResponse);
651             dnsServerResponseCounters->set_other_count(otDnssdCounters.mOtherResponse);
652             // The counters of queries, responses, failures handled by upstream DNS server.
653             dnsServerResponseCounters->set_upstream_dns_queries(otDnssdCounters.mUpstreamDnsCounters.mQueries);
654             dnsServerResponseCounters->set_upstream_dns_responses(otDnssdCounters.mUpstreamDnsCounters.mResponses);
655             dnsServerResponseCounters->set_upstream_dns_failures(otDnssdCounters.mUpstreamDnsCounters.mFailures);
656 
657             dnsServer->set_resolved_by_local_srp_count(otDnssdCounters.mResolvedBySrp);
658 
659             dnsServer->set_upstream_dns_query_state(
660                 otDnssdUpstreamQueryIsEnabled(otInstance)
661                     ? ThreadnetworkTelemetryDataReported::UPSTREAMDNS_QUERY_STATE_ENABLED
662                     : ThreadnetworkTelemetryDataReported::UPSTREAMDNS_QUERY_STATE_DISABLED);
663         }
664         // End of DnsServerInfo section.
665 #endif // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
666 
667         // Start of MdnsInfo section.
668         if (aPublisher != nullptr)
669         {
670             auto                     mdns     = wpanBorderRouter->mutable_mdns();
671             const MdnsTelemetryInfo &mdnsInfo = aPublisher->GetMdnsTelemetryInfo();
672 
673             CopyMdnsResponseCounters(mdnsInfo.mHostRegistrations, mdns->mutable_host_registration_responses());
674             CopyMdnsResponseCounters(mdnsInfo.mServiceRegistrations, mdns->mutable_service_registration_responses());
675             CopyMdnsResponseCounters(mdnsInfo.mHostResolutions, mdns->mutable_host_resolution_responses());
676             CopyMdnsResponseCounters(mdnsInfo.mServiceResolutions, mdns->mutable_service_resolution_responses());
677 
678             mdns->set_host_registration_ema_latency_ms(mdnsInfo.mHostRegistrationEmaLatency);
679             mdns->set_service_registration_ema_latency_ms(mdnsInfo.mServiceRegistrationEmaLatency);
680             mdns->set_host_resolution_ema_latency_ms(mdnsInfo.mHostResolutionEmaLatency);
681             mdns->set_service_resolution_ema_latency_ms(mdnsInfo.mServiceResolutionEmaLatency);
682         }
683         // End of MdnsInfo section.
684 
685         // End of WpanBorderRouter section.
686 
687         // Start of WpanRcp section.
688         {
689             auto                        wpanRcp                = telemetryDataReported.mutable_wpan_rcp();
690             const otRadioSpinelMetrics *otRadioSpinelMetrics   = otSysGetRadioSpinelMetrics();
691             auto                        rcpStabilityStatistics = wpanRcp->mutable_rcp_stability_statistics();
692 
693             if (otRadioSpinelMetrics != nullptr)
694             {
695                 rcpStabilityStatistics->set_rcp_timeout_count(otRadioSpinelMetrics->mRcpTimeoutCount);
696                 rcpStabilityStatistics->set_rcp_reset_count(otRadioSpinelMetrics->mRcpUnexpectedResetCount);
697                 rcpStabilityStatistics->set_rcp_restoration_count(otRadioSpinelMetrics->mRcpRestorationCount);
698                 rcpStabilityStatistics->set_spinel_parse_error_count(otRadioSpinelMetrics->mSpinelParseErrorCount);
699             }
700 
701             // TODO: provide rcp_firmware_update_count info.
702             rcpStabilityStatistics->set_thread_stack_uptime(otInstanceGetUptime(otInstance));
703 
704             const otRcpInterfaceMetrics *otRcpInterfaceMetrics = otSysGetRcpInterfaceMetrics();
705 
706             if (otRcpInterfaceMetrics != nullptr)
707             {
708                 auto rcpInterfaceStatistics = wpanRcp->mutable_rcp_interface_statistics();
709 
710                 rcpInterfaceStatistics->set_rcp_interface_type(otRcpInterfaceMetrics->mRcpInterfaceType);
711                 rcpInterfaceStatistics->set_transferred_frames_count(otRcpInterfaceMetrics->mTransferredFrameCount);
712                 rcpInterfaceStatistics->set_transferred_valid_frames_count(
713                     otRcpInterfaceMetrics->mTransferredValidFrameCount);
714                 rcpInterfaceStatistics->set_transferred_garbage_frames_count(
715                     otRcpInterfaceMetrics->mTransferredGarbageFrameCount);
716                 rcpInterfaceStatistics->set_rx_frames_count(otRcpInterfaceMetrics->mRxFrameCount);
717                 rcpInterfaceStatistics->set_rx_bytes_count(otRcpInterfaceMetrics->mRxFrameByteCount);
718                 rcpInterfaceStatistics->set_tx_frames_count(otRcpInterfaceMetrics->mTxFrameCount);
719                 rcpInterfaceStatistics->set_tx_bytes_count(otRcpInterfaceMetrics->mTxFrameByteCount);
720             }
721         }
722         // End of WpanRcp section.
723 
724         // Start of CoexMetrics section.
725         {
726             auto               coexMetrics = telemetryDataReported.mutable_coex_metrics();
727             otRadioCoexMetrics otRadioCoexMetrics;
728 
729             if (otPlatRadioGetCoexMetrics(otInstance, &otRadioCoexMetrics) == OT_ERROR_NONE)
730             {
731                 coexMetrics->set_count_tx_request(otRadioCoexMetrics.mNumTxRequest);
732                 coexMetrics->set_count_tx_grant_immediate(otRadioCoexMetrics.mNumTxGrantImmediate);
733                 coexMetrics->set_count_tx_grant_wait(otRadioCoexMetrics.mNumTxGrantWait);
734                 coexMetrics->set_count_tx_grant_wait_activated(otRadioCoexMetrics.mNumTxGrantWaitActivated);
735                 coexMetrics->set_count_tx_grant_wait_timeout(otRadioCoexMetrics.mNumTxGrantWaitTimeout);
736                 coexMetrics->set_count_tx_grant_deactivated_during_request(
737                     otRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest);
738                 coexMetrics->set_tx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgTxRequestToGrantTime);
739                 coexMetrics->set_count_rx_request(otRadioCoexMetrics.mNumRxRequest);
740                 coexMetrics->set_count_rx_grant_immediate(otRadioCoexMetrics.mNumRxGrantImmediate);
741                 coexMetrics->set_count_rx_grant_wait(otRadioCoexMetrics.mNumRxGrantWait);
742                 coexMetrics->set_count_rx_grant_wait_activated(otRadioCoexMetrics.mNumRxGrantWaitActivated);
743                 coexMetrics->set_count_rx_grant_wait_timeout(otRadioCoexMetrics.mNumRxGrantWaitTimeout);
744                 coexMetrics->set_count_rx_grant_deactivated_during_request(
745                     otRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest);
746                 coexMetrics->set_count_rx_grant_none(otRadioCoexMetrics.mNumRxGrantNone);
747                 coexMetrics->set_rx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgRxRequestToGrantTime);
748             }
749             else
750             {
751                 error = OT_ERROR_FAILED;
752             }
753         }
754         // End of CoexMetrics section.
755 
756         RetrieveNat64State(otInstance, wpanBorderRouter);
757         RetrieveBorderAgentInfo(otInstance, wpanBorderRouter->mutable_border_agent_info());
758         RetrieveTrelInfo(otInstance, wpanBorderRouter->mutable_trel_info());
759     }
760 
761     return error;
762 }
763 
PushAtom(const ThreadnetworkTelemetryDataReported & telemetryDataReported)764 int PushAtom(const ThreadnetworkTelemetryDataReported &telemetryDataReported)
765 {
766     const std::string        &wpanStats        = telemetryDataReported.wpan_stats().SerializeAsString();
767     const std::string        &wpanTopoFull     = telemetryDataReported.wpan_topo_full().SerializeAsString();
768     const std::string        &wpanBorderRouter = telemetryDataReported.wpan_border_router().SerializeAsString();
769     const std::string        &wpanRcp          = telemetryDataReported.wpan_rcp().SerializeAsString();
770     const std::string        &coexMetrics      = telemetryDataReported.coex_metrics().SerializeAsString();
771     threadnetwork::BytesField wpanStatsBytesField{wpanStats.c_str(), wpanStats.size()};
772     threadnetwork::BytesField wpanTopoFullBytesField{wpanTopoFull.c_str(), wpanTopoFull.size()};
773     threadnetwork::BytesField wpanBorderRouterBytesField{wpanBorderRouter.c_str(), wpanBorderRouter.size()};
774     threadnetwork::BytesField wpanRcpBytesField{wpanRcp.c_str(), wpanRcp.size()};
775     threadnetwork::BytesField coexMetricsBytesField{coexMetrics.c_str(), coexMetrics.size()};
776     return threadnetwork::stats_write(threadnetwork::THREADNETWORK_TELEMETRY_DATA_REPORTED, wpanStatsBytesField,
777                                       wpanTopoFullBytesField, wpanBorderRouterBytesField, wpanRcpBytesField,
778                                       coexMetricsBytesField);
779 }
780 
PushAtom(const ThreadnetworkTopoEntryRepeated & topoEntryRepeated)781 int PushAtom(const ThreadnetworkTopoEntryRepeated &topoEntryRepeated)
782 {
783     const std::string        &topoEntryField = topoEntryRepeated.topo_entry_repeated().SerializeAsString();
784     threadnetwork::BytesField topoEntryFieldBytesField{topoEntryField.c_str(), topoEntryField.size()};
785     return threadnetwork::stats_write(threadnetwork::THREADNETWORK_TOPO_ENTRY_REPEATED, topoEntryFieldBytesField);
786 }
787 
PushAtom(const ThreadnetworkDeviceInfoReported & deviceInfoReported)788 int PushAtom(const ThreadnetworkDeviceInfoReported &deviceInfoReported)
789 {
790     const std::string &otHostVersion       = deviceInfoReported.ot_host_version();
791     const std::string &otRcpVersion        = deviceInfoReported.ot_rcp_version();
792     const int32_t     &threadVersion       = deviceInfoReported.thread_version();
793     const std::string &threadDaemonVersion = deviceInfoReported.thread_daemon_version();
794     return threadnetwork::stats_write(threadnetwork::THREADNETWORK_DEVICE_INFO_REPORTED, otHostVersion.c_str(),
795                                       otRcpVersion.c_str(), threadVersion, threadDaemonVersion.c_str());
796 }
797 
RetrieveAndPushAtoms(otInstance * otInstance)798 void RetrieveAndPushAtoms(otInstance *otInstance)
799 {
800     ThreadnetworkTelemetryDataReported telemetryDataReported;
801     ThreadnetworkTopoEntryRepeated     topoEntryRepeated;
802     ThreadnetworkDeviceInfoReported    deviceInfoReported;
803 
804     otbrLogInfo("Try to push threadnetwork ATOMs.");
805     if (RetrieveTelemetryAtom(otInstance, nullptr, telemetryDataReported, topoEntryRepeated, deviceInfoReported) !=
806         OTBR_ERROR_NONE)
807     {
808         otbrLogWarning("Some telemetries are not populated");
809     }
810     if (PushAtom(telemetryDataReported) <= 0)
811     {
812         otbrLogWarning("Failed to push ThreadnetworkTelemetryDataReported");
813     }
814     if (PushAtom(topoEntryRepeated) <= 0)
815     {
816         otbrLogWarning("Failed to push ThreadnetworkTopoEntryRepeated");
817     }
818     if (PushAtom(deviceInfoReported) <= 0)
819     {
820         otbrLogWarning("Failed to push ThreadnetworkDeviceInfoReported");
821     }
822     otbrLogInfo("Pushed threadnetwork ATOMs.");
823 }
824 } // namespace Android
825 } // namespace otbr
826