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