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