1 /*
2 * Copyright (c) 2020, 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
29 /**
30 * @file
31 * This file implements OTNS utilities.
32 */
33
34 #include "otns.hpp"
35
36 #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
37
38 #include "instance/instance.hpp"
39
40 namespace ot {
41 namespace Utils {
42
43 RegisterLogModule("Otns");
44
45 const int kMaxStatusStringLength = 128;
46
EmitShortAddress(uint16_t aShortAddress)47 void Otns::EmitShortAddress(uint16_t aShortAddress) { EmitStatus("rloc16=%d", aShortAddress); }
48
EmitExtendedAddress(const Mac::ExtAddress & aExtAddress)49 void Otns::EmitExtendedAddress(const Mac::ExtAddress &aExtAddress)
50 {
51 Mac::ExtAddress revExtAddress;
52 revExtAddress.Set(aExtAddress.m8, Mac::ExtAddress::kReverseByteOrder);
53 EmitStatus("extaddr=%s", revExtAddress.ToString().AsCString());
54 }
55
EmitPingRequest(const Ip6::Address & aPeerAddress,uint16_t aPingLength,uint32_t aTimestamp,uint8_t aHopLimit)56 void Otns::EmitPingRequest(const Ip6::Address &aPeerAddress,
57 uint16_t aPingLength,
58 uint32_t aTimestamp,
59 uint8_t aHopLimit)
60 {
61 OT_UNUSED_VARIABLE(aHopLimit);
62 EmitStatus("ping_request=%s,%d,%lu", aPeerAddress.ToString().AsCString(), aPingLength, aTimestamp);
63 }
64
EmitPingReply(const Ip6::Address & aPeerAddress,uint16_t aPingLength,uint32_t aTimestamp,uint8_t aHopLimit)65 void Otns::EmitPingReply(const Ip6::Address &aPeerAddress, uint16_t aPingLength, uint32_t aTimestamp, uint8_t aHopLimit)
66 {
67 EmitStatus("ping_reply=%s,%u,%lu,%d", aPeerAddress.ToString().AsCString(), aPingLength, aTimestamp, aHopLimit);
68 }
69
EmitStatus(const char * aFmt,...)70 void Otns::EmitStatus(const char *aFmt, ...)
71 {
72 char statusStr[kMaxStatusStringLength + 1];
73 int n;
74
75 va_list ap;
76 va_start(ap, aFmt);
77
78 n = vsnprintf(statusStr, sizeof(statusStr), aFmt, ap);
79 OT_UNUSED_VARIABLE(n);
80 OT_ASSERT(n >= 0);
81
82 va_end(ap);
83
84 otPlatOtnsStatus(statusStr);
85 }
86
HandleNotifierEvents(Events aEvents)87 void Otns::HandleNotifierEvents(Events aEvents)
88 {
89 if (aEvents.Contains(kEventThreadRoleChanged))
90 {
91 EmitStatus("role=%d", Get<Mle::Mle>().GetRole());
92 }
93
94 if (aEvents.Contains(kEventThreadPartitionIdChanged))
95 {
96 EmitStatus("parid=%x", Get<Mle::Mle>().GetLeaderData().GetPartitionId());
97 }
98
99 #if OPENTHREAD_CONFIG_JOINER_ENABLE
100 if (aEvents.Contains(kEventJoinerStateChanged))
101 {
102 EmitStatus("joiner_state=%d", Get<MeshCoP::Joiner>().GetState());
103 }
104 #endif
105 }
106
EmitNeighborChange(NeighborTable::Event aEvent,const Neighbor & aNeighbor)107 void Otns::EmitNeighborChange(NeighborTable::Event aEvent, const Neighbor &aNeighbor)
108 {
109 switch (aEvent)
110 {
111 case NeighborTable::kRouterAdded:
112 EmitStatus("router_added=%s", aNeighbor.GetExtAddress().ToString().AsCString());
113 break;
114 case NeighborTable::kRouterRemoved:
115 EmitStatus("router_removed=%s", aNeighbor.GetExtAddress().ToString().AsCString());
116 break;
117 case NeighborTable::kChildAdded:
118 EmitStatus("child_added=%s", aNeighbor.GetExtAddress().ToString().AsCString());
119 break;
120 case NeighborTable::kChildRemoved:
121 EmitStatus("child_removed=%s", aNeighbor.GetExtAddress().ToString().AsCString());
122 break;
123 case NeighborTable::kChildModeChanged:
124 break;
125 }
126 }
127
EmitTransmit(const Mac::TxFrame & aFrame)128 void Otns::EmitTransmit(const Mac::TxFrame &aFrame)
129 {
130 Mac::Address dst;
131 uint16_t frameControlField = aFrame.GetFrameControlField();
132 uint8_t channel = aFrame.GetChannel();
133 uint8_t sequence = aFrame.GetSequence();
134
135 IgnoreError(aFrame.GetDstAddr(dst));
136
137 if (dst.IsShort())
138 {
139 EmitStatus("transmit=%d,%04x,%d,%04x", channel, frameControlField, sequence, dst.GetShort());
140 }
141 else if (dst.IsExtended())
142 {
143 EmitStatus("transmit=%d,%04x,%d,%s", channel, frameControlField, sequence, dst.ToString().AsCString());
144 }
145 else
146 {
147 EmitStatus("transmit=%d,%04x,%d", channel, frameControlField, sequence);
148 }
149 }
150
EmitDeviceMode(Mle::DeviceMode aMode)151 void Otns::EmitDeviceMode(Mle::DeviceMode aMode)
152 {
153 EmitStatus("mode=%s%s%s", aMode.IsRxOnWhenIdle() ? "r" : "", aMode.IsFullThreadDevice() ? "d" : "",
154 (aMode.GetNetworkDataType() == NetworkData::kFullSet) ? "n" : "");
155 }
156
EmitCoapSend(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)157 void Otns::EmitCoapSend(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
158 {
159 char uriPath[Coap::Message::kMaxReceivedUriPath + 1];
160 Error error;
161
162 SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
163
164 EmitStatus("coap=send,%d,%d,%d,%s,%s,%d", aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(), uriPath,
165 aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort());
166
167 exit:
168 LogWarnOnError(error, "EmitCoapSend");
169 }
170
EmitCoapReceive(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)171 void Otns::EmitCoapReceive(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
172 {
173 char uriPath[Coap::Message::kMaxReceivedUriPath + 1];
174 Error error = kErrorNone;
175
176 SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
177
178 EmitStatus("coap=recv,%d,%d,%d,%s,%s,%d", aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(), uriPath,
179 aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort());
180 exit:
181 LogWarnOnError(error, "EmitCoapReceive");
182 }
183
EmitCoapSendFailure(Error aError,Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)184 void Otns::EmitCoapSendFailure(Error aError, Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
185 {
186 char uriPath[Coap::Message::kMaxReceivedUriPath + 1];
187 Error error = kErrorNone;
188
189 SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
190
191 EmitStatus("coap=send_error,%d,%d,%d,%s,%s,%d,%s", aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(),
192 uriPath, aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort(),
193 ErrorToString(aError));
194 exit:
195 LogWarnOnError(error, "EmitCoapSendFailure");
196 }
197
198 } // namespace Utils
199 } // namespace ot
200
201 #endif // (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
202