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