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 Thread Management Framework (TMF) functionalities.
32  */
33 
34 #include "thread/tmf.hpp"
35 
36 #include "common/locator_getters.hpp"
37 #include "net/ip6_types.hpp"
38 
39 namespace ot {
40 namespace Tmf {
41 
42 //----------------------------------------------------------------------------------------------------------------------
43 // MessageInfo
44 
SetSockAddrToRloc(void)45 void MessageInfo::SetSockAddrToRloc(void) { SetSockAddr(Get<Mle::MleRouter>().GetMeshLocal16()); }
46 
SetSockAddrToRlocPeerAddrToLeaderAloc(void)47 Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderAloc(void)
48 {
49     SetSockAddrToRloc();
50     return Get<Mle::MleRouter>().GetLeaderAloc(GetPeerAddr());
51 }
52 
SetSockAddrToRlocPeerAddrToLeaderRloc(void)53 Error MessageInfo::SetSockAddrToRlocPeerAddrToLeaderRloc(void)
54 {
55     SetSockAddrToRloc();
56     return Get<Mle::MleRouter>().GetLeaderAddress(GetPeerAddr());
57 }
58 
SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void)59 void MessageInfo::SetSockAddrToRlocPeerAddrToRealmLocalAllRoutersMulticast(void)
60 {
61     SetSockAddrToRloc();
62     GetPeerAddr().SetToRealmLocalAllRoutersMulticast();
63 }
64 
SetSockAddrToRlocPeerAddrTo(uint16_t aRloc16)65 void MessageInfo::SetSockAddrToRlocPeerAddrTo(uint16_t aRloc16)
66 {
67     SetSockAddrToRloc();
68     SetPeerAddr(Get<Mle::MleRouter>().GetMeshLocal16());
69     GetPeerAddr().GetIid().SetLocator(aRloc16);
70 }
71 
SetSockAddrToRlocPeerAddrTo(const Ip6::Address & aPeerAddress)72 void MessageInfo::SetSockAddrToRlocPeerAddrTo(const Ip6::Address &aPeerAddress)
73 {
74     SetSockAddrToRloc();
75     SetPeerAddr(aPeerAddress);
76 }
77 
78 //----------------------------------------------------------------------------------------------------------------------
79 // Agent
80 
Agent(Instance & aInstance)81 Agent::Agent(Instance &aInstance)
82     : Coap::Coap(aInstance)
83 {
84     SetInterceptor(&Filter, this);
85     SetResourceHandler(&HandleResource);
86 }
87 
Start(void)88 Error Agent::Start(void) { return Coap::Start(kUdpPort, Ip6::kNetifThread); }
89 
HandleTmf(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)90 template <> void Agent::HandleTmf<kUriRelayRx>(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
91 {
92     OT_UNUSED_VARIABLE(aMessage);
93     OT_UNUSED_VARIABLE(aMessageInfo);
94 
95 #if (OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE)
96     Get<MeshCoP::Commissioner>().HandleTmf<kUriRelayRx>(aMessage, aMessageInfo);
97 #endif
98 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
99     Get<MeshCoP::BorderAgent>().HandleTmf<kUriRelayRx>(aMessage, aMessageInfo);
100 #endif
101 }
102 
HandleResource(CoapBase & aCoapBase,const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)103 bool Agent::HandleResource(CoapBase               &aCoapBase,
104                            const char             *aUriPath,
105                            Message                &aMessage,
106                            const Ip6::MessageInfo &aMessageInfo)
107 {
108     return static_cast<Agent &>(aCoapBase).HandleResource(aUriPath, aMessage, aMessageInfo);
109 }
110 
HandleResource(const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)111 bool Agent::HandleResource(const char *aUriPath, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
112 {
113     bool didHandle = true;
114     Uri  uri       = UriFromPath(aUriPath);
115 
116 #define Case(kUri, Type)                                     \
117     case kUri:                                               \
118         Get<Type>().HandleTmf<kUri>(aMessage, aMessageInfo); \
119         break
120 
121     switch (uri)
122     {
123         Case(kUriAddressError, AddressResolver);
124         Case(kUriEnergyScan, EnergyScanServer);
125         Case(kUriActiveGet, MeshCoP::ActiveDatasetManager);
126         Case(kUriPendingGet, MeshCoP::PendingDatasetManager);
127         Case(kUriPanIdQuery, PanIdQueryServer);
128 
129 #if OPENTHREAD_FTD
130         Case(kUriAddressQuery, AddressResolver);
131         Case(kUriAddressNotify, AddressResolver);
132         Case(kUriAddressSolicit, Mle::MleRouter);
133         Case(kUriAddressRelease, Mle::MleRouter);
134         Case(kUriActiveSet, MeshCoP::ActiveDatasetManager);
135         Case(kUriPendingSet, MeshCoP::PendingDatasetManager);
136         Case(kUriLeaderPetition, MeshCoP::Leader);
137         Case(kUriLeaderKeepAlive, MeshCoP::Leader);
138         Case(kUriServerData, NetworkData::Leader);
139         Case(kUriCommissionerGet, NetworkData::Leader);
140         Case(kUriCommissionerSet, NetworkData::Leader);
141         Case(kUriAnnounceBegin, AnnounceBeginServer);
142         Case(kUriRelayTx, MeshCoP::JoinerRouter);
143 #endif
144 
145 #if OPENTHREAD_CONFIG_JOINER_ENABLE
146         Case(kUriJoinerEntrust, MeshCoP::Joiner);
147 #endif
148 
149 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
150         Case(kUriPanIdConflict, PanIdQueryClient);
151         Case(kUriEnergyReport, EnergyScanClient);
152         Case(kUriDatasetChanged, MeshCoP::Commissioner);
153         // kUriRelayRx is handled below
154 #endif
155 
156 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE)
157         Case(kUriRelayRx, Agent);
158 #endif
159 
160 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
161         Case(kUriDuaRegistrationNotify, DuaManager);
162 #endif
163 
164 #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
165         Case(kUriAnycastLocate, AnycastLocator);
166 #endif
167 
168         Case(kUriDiagnosticGetRequest, NetworkDiagnostic::Server);
169         Case(kUriDiagnosticGetQuery, NetworkDiagnostic::Server);
170         Case(kUriDiagnosticReset, NetworkDiagnostic::Server);
171 
172 #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
173         Case(kUriDiagnosticGetAnswer, NetworkDiagnostic::Client);
174 #endif
175 
176 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
177 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
178         Case(kUriMlr, BackboneRouter::Manager);
179 #endif
180 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
181         Case(kUriDuaRegistrationRequest, BackboneRouter::Manager);
182 #endif
183 #endif
184 
185     default:
186         didHandle = false;
187         break;
188     }
189 
190 #undef Case
191 
192     return didHandle;
193 }
194 
Filter(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo,void * aContext)195 Error Agent::Filter(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext)
196 {
197     OT_UNUSED_VARIABLE(aMessage);
198 
199     return static_cast<Agent *>(aContext)->IsTmfMessage(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(),
200                                                         aMessageInfo.GetSockPort())
201                ? kErrorNone
202                : kErrorNotTmf;
203 }
204 
IsTmfMessage(const Ip6::Address & aSourceAddress,const Ip6::Address & aDestAddress,uint16_t aDestPort) const205 bool Agent::IsTmfMessage(const Ip6::Address &aSourceAddress, const Ip6::Address &aDestAddress, uint16_t aDestPort) const
206 {
207     bool isTmf = false;
208 
209     VerifyOrExit(aDestPort == kUdpPort);
210 
211     if (aSourceAddress.IsLinkLocal())
212     {
213         isTmf = aDestAddress.IsLinkLocal() || aDestAddress.IsLinkLocalMulticast();
214         ExitNow();
215     }
216 
217     VerifyOrExit(Get<Mle::Mle>().IsMeshLocalAddress(aSourceAddress));
218     VerifyOrExit(Get<Mle::Mle>().IsMeshLocalAddress(aDestAddress) || aDestAddress.IsLinkLocalMulticast() ||
219                  aDestAddress.IsRealmLocalMulticast());
220 
221     isTmf = true;
222 
223 exit:
224     return isTmf;
225 }
226 
PriorityToDscp(Message::Priority aPriority)227 uint8_t Agent::PriorityToDscp(Message::Priority aPriority)
228 {
229     uint8_t dscp = Ip6::kDscpTmfNormalPriority;
230 
231     switch (aPriority)
232     {
233     case Message::kPriorityNet:
234         dscp = Ip6::kDscpTmfNetPriority;
235         break;
236 
237     case Message::kPriorityHigh:
238     case Message::kPriorityNormal:
239         break;
240 
241     case Message::kPriorityLow:
242         dscp = Ip6::kDscpTmfLowPriority;
243         break;
244     }
245 
246     return dscp;
247 }
248 
DscpToPriority(uint8_t aDscp)249 Message::Priority Agent::DscpToPriority(uint8_t aDscp)
250 {
251     Message::Priority priority = Message::kPriorityNet;
252 
253     // If the sender does not use TMF specific DSCP value, we use
254     // `kPriorityNet`. This ensures that senders that do not use the
255     // new value (older firmware) experience the same behavior as
256     // before where all TMF message were treated as `kPriorityNet`.
257 
258     switch (aDscp)
259     {
260     case Ip6::kDscpTmfNetPriority:
261     default:
262         break;
263     case Ip6::kDscpTmfNormalPriority:
264         priority = Message::kPriorityNormal;
265         break;
266     case Ip6::kDscpTmfLowPriority:
267         priority = Message::kPriorityLow;
268         break;
269     }
270 
271     return priority;
272 }
273 
274 #if OPENTHREAD_CONFIG_DTLS_ENABLE
275 
SecureAgent(Instance & aInstance)276 SecureAgent::SecureAgent(Instance &aInstance)
277     : Coap::CoapSecure(aInstance)
278 {
279     SetResourceHandler(&HandleResource);
280 }
281 
HandleResource(CoapBase & aCoapBase,const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)282 bool SecureAgent::HandleResource(CoapBase               &aCoapBase,
283                                  const char             *aUriPath,
284                                  Message                &aMessage,
285                                  const Ip6::MessageInfo &aMessageInfo)
286 {
287     return static_cast<SecureAgent &>(aCoapBase).HandleResource(aUriPath, aMessage, aMessageInfo);
288 }
289 
HandleResource(const char * aUriPath,Message & aMessage,const Ip6::MessageInfo & aMessageInfo)290 bool SecureAgent::HandleResource(const char *aUriPath, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
291 {
292     OT_UNUSED_VARIABLE(aMessage);
293     OT_UNUSED_VARIABLE(aMessageInfo);
294 
295     bool didHandle = true;
296     Uri  uri       = UriFromPath(aUriPath);
297 
298 #define Case(kUri, Type)                                     \
299     case kUri:                                               \
300         Get<Type>().HandleTmf<kUri>(aMessage, aMessageInfo); \
301         break
302 
303     switch (uri)
304     {
305 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
306         Case(kUriJoinerFinalize, MeshCoP::Commissioner);
307 #endif
308 
309 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
310         Case(kUriCommissionerPetition, MeshCoP::BorderAgent);
311         Case(kUriCommissionerKeepAlive, MeshCoP::BorderAgent);
312         Case(kUriRelayTx, MeshCoP::BorderAgent);
313         Case(kUriCommissionerGet, MeshCoP::BorderAgent);
314         Case(kUriCommissionerSet, MeshCoP::BorderAgent);
315         Case(kUriActiveGet, MeshCoP::BorderAgent);
316         Case(kUriActiveSet, MeshCoP::BorderAgent);
317         Case(kUriPendingGet, MeshCoP::BorderAgent);
318         Case(kUriPendingSet, MeshCoP::BorderAgent);
319         Case(kUriProxyTx, MeshCoP::BorderAgent);
320 #endif
321 
322     default:
323         didHandle = false;
324         break;
325     }
326 
327 #undef Case
328 
329     return didHandle;
330 }
331 
332 #endif // OPENTHREAD_CONFIG_DTLS_ENABLE
333 
334 } // namespace Tmf
335 } // namespace ot
336