1 /*
2  *  Copyright (c) 2018, 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 the BorderAgent service.
32  */
33 
34 #include "border_agent.hpp"
35 
36 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
37 
38 #include "coap/coap_message.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/heap.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/owned_ptr.hpp"
44 #include "common/settings.hpp"
45 #include "instance/instance.hpp"
46 #include "meshcop/meshcop.hpp"
47 #include "meshcop/meshcop_tlvs.hpp"
48 #include "thread/thread_netif.hpp"
49 #include "thread/thread_tlvs.hpp"
50 #include "thread/uri_paths.hpp"
51 
52 namespace ot {
53 namespace MeshCoP {
54 
55 RegisterLogModule("BorderAgent");
56 
57 //----------------------------------------------------------------------------------------------------------------------
58 // `BorderAgent::ForwardContext`
59 
Init(Instance & aInstance,const Coap::Message & aMessage,bool aPetition,bool aSeparate)60 Error BorderAgent::ForwardContext::Init(Instance            &aInstance,
61                                         const Coap::Message &aMessage,
62                                         bool                 aPetition,
63                                         bool                 aSeparate)
64 {
65     InstanceLocatorInit::Init(aInstance);
66     mMessageId   = aMessage.GetMessageId();
67     mPetition    = aPetition;
68     mSeparate    = aSeparate;
69     mType        = aMessage.GetType();
70     mTokenLength = aMessage.GetTokenLength();
71     memcpy(mToken, aMessage.GetToken(), mTokenLength);
72 
73     return kErrorNone;
74 }
75 
ToHeader(Coap::Message & aMessage,uint8_t aCode) const76 Error BorderAgent::ForwardContext::ToHeader(Coap::Message &aMessage, uint8_t aCode) const
77 {
78     if ((mType == Coap::kTypeNonConfirmable) || mSeparate)
79     {
80         aMessage.Init(Coap::kTypeNonConfirmable, static_cast<Coap::Code>(aCode));
81     }
82     else
83     {
84         aMessage.Init(Coap::kTypeAck, static_cast<Coap::Code>(aCode));
85     }
86 
87     if (!mSeparate)
88     {
89         aMessage.SetMessageId(mMessageId);
90     }
91 
92     return aMessage.SetToken(mToken, mTokenLength);
93 }
94 
95 //----------------------------------------------------------------------------------------------------------------------
96 // `BorderAgent`
97 
CoapCodeFromError(Error aError)98 Coap::Message::Code BorderAgent::CoapCodeFromError(Error aError)
99 {
100     Coap::Message::Code code;
101 
102     switch (aError)
103     {
104     case kErrorNone:
105         code = Coap::kCodeChanged;
106         break;
107 
108     case kErrorParse:
109         code = Coap::kCodeBadRequest;
110         break;
111 
112     default:
113         code = Coap::kCodeInternalError;
114         break;
115     }
116 
117     return code;
118 }
119 
SendErrorMessage(const ForwardContext & aForwardContext,Error aError)120 void BorderAgent::SendErrorMessage(const ForwardContext &aForwardContext, Error aError)
121 {
122     Error          error   = kErrorNone;
123     Coap::Message *message = nullptr;
124 
125     VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
126     SuccessOrExit(error = aForwardContext.ToHeader(*message, CoapCodeFromError(aError)));
127     SuccessOrExit(error = SendMessage(*message));
128 
129 exit:
130     FreeMessageOnError(message, error);
131     LogError("send error CoAP message", error);
132 }
133 
SendErrorMessage(const Coap::Message & aRequest,bool aSeparate,Error aError)134 void BorderAgent::SendErrorMessage(const Coap::Message &aRequest, bool aSeparate, Error aError)
135 {
136     Error          error   = kErrorNone;
137     Coap::Message *message = nullptr;
138 
139     VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
140 
141     if (aRequest.IsNonConfirmable() || aSeparate)
142     {
143         message->Init(Coap::kTypeNonConfirmable, CoapCodeFromError(aError));
144     }
145     else
146     {
147         message->Init(Coap::kTypeAck, CoapCodeFromError(aError));
148     }
149 
150     if (!aSeparate)
151     {
152         message->SetMessageId(aRequest.GetMessageId());
153     }
154 
155     SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
156 
157     SuccessOrExit(error = SendMessage(*message));
158 
159 exit:
160     FreeMessageOnError(message, error);
161     LogError("send error CoAP message", error);
162 }
163 
SendMessage(Coap::Message & aMessage)164 Error BorderAgent::SendMessage(Coap::Message &aMessage)
165 {
166     return Get<Tmf::SecureAgent>().SendMessage(aMessage, Get<Tmf::SecureAgent>().GetMessageInfo());
167 }
168 
HandleCoapResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)169 void BorderAgent::HandleCoapResponse(void                *aContext,
170                                      otMessage           *aMessage,
171                                      const otMessageInfo *aMessageInfo,
172                                      Error                aResult)
173 {
174     OT_UNUSED_VARIABLE(aMessageInfo);
175 
176     OwnedPtr<ForwardContext> forwardContext(static_cast<ForwardContext *>(aContext));
177 
178     forwardContext->Get<BorderAgent>().HandleCoapResponse(*forwardContext.Get(), AsCoapMessagePtr(aMessage), aResult);
179 }
180 
HandleCoapResponse(const ForwardContext & aForwardContext,const Coap::Message * aResponse,Error aResult)181 void BorderAgent::HandleCoapResponse(const ForwardContext &aForwardContext,
182                                      const Coap::Message  *aResponse,
183                                      Error                 aResult)
184 {
185     Coap::Message *message = nullptr;
186     Error          error;
187 
188     SuccessOrExit(error = aResult);
189     VerifyOrExit((message = Get<Tmf::SecureAgent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
190 
191     if (aForwardContext.IsPetition() && aResponse->GetCode() == Coap::kCodeChanged)
192     {
193         uint8_t state;
194 
195         SuccessOrExit(error = Tlv::Find<StateTlv>(*aResponse, state));
196 
197         if (state == StateTlv::kAccept)
198         {
199             uint16_t sessionId;
200 
201             SuccessOrExit(error = Tlv::Find<CommissionerSessionIdTlv>(*aResponse, sessionId));
202 
203             IgnoreError(Get<Mle::MleRouter>().GetCommissionerAloc(mCommissionerAloc.GetAddress(), sessionId));
204             Get<ThreadNetif>().AddUnicastAddress(mCommissionerAloc);
205             IgnoreError(Get<Ip6::Udp>().AddReceiver(mUdpReceiver));
206 
207             LogInfo("Commissioner accepted - SessionId:%u ALOC:%s", sessionId,
208                     mCommissionerAloc.GetAddress().ToString().AsCString());
209         }
210     }
211 
212     SuccessOrExit(error = aForwardContext.ToHeader(*message, aResponse->GetCode()));
213 
214     if (aResponse->GetLength() > aResponse->GetOffset())
215     {
216         SuccessOrExit(error = message->SetPayloadMarker());
217     }
218 
219     SuccessOrExit(error = ForwardToCommissioner(*message, *aResponse));
220 
221 exit:
222 
223     if (error != kErrorNone)
224     {
225         FreeMessage(message);
226 
227         LogWarn("Commissioner request[%u] failed: %s", aForwardContext.GetMessageId(), ErrorToString(error));
228 
229         SendErrorMessage(aForwardContext, error);
230     }
231 }
232 
BorderAgent(Instance & aInstance)233 BorderAgent::BorderAgent(Instance &aInstance)
234     : InstanceLocator(aInstance)
235     , mState(kStateStopped)
236     , mUdpProxyPort(0)
237     , mUdpReceiver(BorderAgent::HandleUdpReceive, this)
238     , mTimer(aInstance)
239 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
240     , mIdInitialized(false)
241 #endif
242 {
243     mCommissionerAloc.InitAsThreadOriginMeshLocal();
244 }
245 
246 #if OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
GetId(Id & aId)247 Error BorderAgent::GetId(Id &aId)
248 {
249     Error                   error = kErrorNone;
250     Settings::BorderAgentId id;
251 
252     VerifyOrExit(!mIdInitialized, error = kErrorNone);
253 
254     if (Get<Settings>().Read(id) != kErrorNone)
255     {
256         Random::NonCrypto::Fill(id.GetId());
257         SuccessOrExit(error = Get<Settings>().Save(id));
258     }
259 
260     mId            = id.GetId();
261     mIdInitialized = true;
262 
263 exit:
264     if (error == kErrorNone)
265     {
266         aId = mId;
267     }
268     return error;
269 }
270 
SetId(const Id & aId)271 Error BorderAgent::SetId(const Id &aId)
272 {
273     Error                   error = kErrorNone;
274     Settings::BorderAgentId id;
275 
276     id.SetId(aId);
277     SuccessOrExit(error = Get<Settings>().Save(id));
278     mId            = aId;
279     mIdInitialized = true;
280 
281 exit:
282     return error;
283 }
284 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
285 
HandleNotifierEvents(Events aEvents)286 void BorderAgent::HandleNotifierEvents(Events aEvents)
287 {
288     VerifyOrExit(aEvents.ContainsAny(kEventThreadRoleChanged | kEventCommissionerStateChanged));
289 
290 #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
291     VerifyOrExit(Get<Commissioner>().IsDisabled());
292 #endif
293 
294     if (Get<Mle::MleRouter>().IsAttached())
295     {
296         Start();
297     }
298     else
299     {
300         Stop();
301     }
302 
303 exit:
304     return;
305 }
306 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)307 template <> void BorderAgent::HandleTmf<kUriProxyTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
308 {
309     OT_UNUSED_VARIABLE(aMessageInfo);
310 
311     Error                     error   = kErrorNone;
312     Message                  *message = nullptr;
313     Ip6::MessageInfo          messageInfo;
314     uint16_t                  offset;
315     uint16_t                  length;
316     UdpEncapsulationTlvHeader udpEncapHeader;
317 
318     VerifyOrExit(mState != kStateStopped);
319 
320     SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Tlv::kUdpEncapsulation, offset, length));
321 
322     SuccessOrExit(error = aMessage.Read(offset, udpEncapHeader));
323     offset += sizeof(UdpEncapsulationTlvHeader);
324     length -= sizeof(UdpEncapsulationTlvHeader);
325 
326     VerifyOrExit(udpEncapHeader.GetSourcePort() > 0 && udpEncapHeader.GetDestinationPort() > 0, error = kErrorDrop);
327 
328     VerifyOrExit((message = Get<Ip6::Udp>().NewMessage()) != nullptr, error = kErrorNoBufs);
329     SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offset, length));
330 
331     messageInfo.SetSockPort(udpEncapHeader.GetSourcePort());
332     messageInfo.SetSockAddr(mCommissionerAloc.GetAddress());
333     messageInfo.SetPeerPort(udpEncapHeader.GetDestinationPort());
334 
335     SuccessOrExit(error = Tlv::Find<Ip6AddressTlv>(aMessage, messageInfo.GetPeerAddr()));
336 
337     SuccessOrExit(error = Get<Ip6::Udp>().SendDatagram(*message, messageInfo));
338     mUdpProxyPort = udpEncapHeader.GetSourcePort();
339 
340     LogInfo("Proxy transmit sent to %s", messageInfo.GetPeerAddr().ToString().AsCString());
341 
342 exit:
343     FreeMessageOnError(message, error);
344     LogError("send proxy stream", error);
345 }
346 
HandleUdpReceive(void * aContext,const otMessage * aMessage,const otMessageInfo * aMessageInfo)347 bool BorderAgent::HandleUdpReceive(void *aContext, const otMessage *aMessage, const otMessageInfo *aMessageInfo)
348 {
349     return static_cast<BorderAgent *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
350 }
351 
HandleUdpReceive(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo)352 bool BorderAgent::HandleUdpReceive(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
353 {
354     Error          error;
355     Coap::Message *message = nullptr;
356 
357     if (aMessageInfo.GetSockAddr() != mCommissionerAloc.GetAddress())
358     {
359         LogDebg("Filtered out message for commissioner: dest %s != %s (ALOC)",
360                 aMessageInfo.GetSockAddr().ToString().AsCString(),
361                 mCommissionerAloc.GetAddress().ToString().AsCString());
362         ExitNow(error = kErrorDestinationAddressFiltered);
363     }
364 
365     VerifyOrExit(aMessage.GetLength() > 0, error = kErrorNone);
366 
367     message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriProxyRx);
368     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
369 
370     {
371         ExtendedTlv               extTlv;
372         UdpEncapsulationTlvHeader udpEncapHeader;
373         uint16_t                  udpLength = aMessage.GetLength() - aMessage.GetOffset();
374 
375         extTlv.SetType(Tlv::kUdpEncapsulation);
376         extTlv.SetLength(sizeof(UdpEncapsulationTlvHeader) + udpLength);
377         SuccessOrExit(error = message->Append(extTlv));
378 
379         udpEncapHeader.SetSourcePort(aMessageInfo.GetPeerPort());
380         udpEncapHeader.SetDestinationPort(aMessageInfo.GetSockPort());
381         SuccessOrExit(error = message->Append(udpEncapHeader));
382         SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(), udpLength));
383     }
384 
385     SuccessOrExit(error = Tlv::Append<Ip6AddressTlv>(*message, aMessageInfo.GetPeerAddr()));
386 
387     SuccessOrExit(error = SendMessage(*message));
388 
389     LogInfo("Sent to commissioner on ProxyRx (c/ur)");
390 
391 exit:
392     FreeMessageOnError(message, error);
393     if (error != kErrorDestinationAddressFiltered)
394     {
395         LogError("notify commissioner on ProxyRx (c/ur)", error);
396     }
397 
398     return error != kErrorDestinationAddressFiltered;
399 }
400 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)401 template <> void BorderAgent::HandleTmf<kUriRelayRx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
402 {
403     OT_UNUSED_VARIABLE(aMessageInfo);
404 
405     Coap::Message *message = nullptr;
406     Error          error   = kErrorNone;
407 
408     VerifyOrExit(mState != kStateStopped);
409 
410     VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);
411 
412     message = Get<Tmf::SecureAgent>().NewPriorityNonConfirmablePostMessage(kUriRelayRx);
413     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
414 
415     SuccessOrExit(error = ForwardToCommissioner(*message, aMessage));
416     LogInfo("Sent to commissioner on RelayRx (c/rx)");
417 
418 exit:
419     FreeMessageOnError(message, error);
420 }
421 
ForwardToCommissioner(Coap::Message & aForwardMessage,const Message & aMessage)422 Error BorderAgent::ForwardToCommissioner(Coap::Message &aForwardMessage, const Message &aMessage)
423 {
424     Error error;
425 
426     SuccessOrExit(error = aForwardMessage.AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
427                                                                  aMessage.GetLength() - aMessage.GetOffset()));
428     SuccessOrExit(error = SendMessage(aForwardMessage));
429 
430     LogInfo("Sent to commissioner");
431 
432 exit:
433     LogError("send to commissioner", error);
434     return error;
435 }
436 
437 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)438 void BorderAgent::HandleTmf<kUriCommissionerPetition>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
439 {
440     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderPetition));
441 }
442 
443 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)444 void BorderAgent::HandleTmf<kUriCommissionerGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
445 {
446     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriCommissionerGet));
447 }
448 
449 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)450 void BorderAgent::HandleTmf<kUriCommissionerSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
451 {
452     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriCommissionerSet));
453 }
454 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)455 template <> void BorderAgent::HandleTmf<kUriActiveGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
456 {
457     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriActiveGet));
458 }
459 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)460 template <> void BorderAgent::HandleTmf<kUriActiveSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
461 {
462     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriActiveSet));
463 }
464 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)465 template <> void BorderAgent::HandleTmf<kUriPendingGet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
466 {
467     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriPendingGet));
468 }
469 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)470 template <> void BorderAgent::HandleTmf<kUriPendingSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
471 {
472     IgnoreError(ForwardToLeader(aMessage, aMessageInfo, kUriPendingSet));
473 }
474 
475 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)476 void BorderAgent::HandleTmf<kUriCommissionerKeepAlive>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
477 {
478     VerifyOrExit(mState != kStateStopped);
479 
480     SuccessOrExit(ForwardToLeader(aMessage, aMessageInfo, kUriLeaderKeepAlive));
481     mTimer.Start(kKeepAliveTimeout);
482 
483 exit:
484     return;
485 }
486 
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)487 template <> void BorderAgent::HandleTmf<kUriRelayTx>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
488 {
489     OT_UNUSED_VARIABLE(aMessageInfo);
490 
491     Error            error = kErrorNone;
492     uint16_t         joinerRouterRloc;
493     Coap::Message   *message = nullptr;
494     Tmf::MessageInfo messageInfo(GetInstance());
495 
496     VerifyOrExit(mState != kStateStopped);
497 
498     VerifyOrExit(aMessage.IsNonConfirmablePostRequest());
499 
500     SuccessOrExit(error = Tlv::Find<JoinerRouterLocatorTlv>(aMessage, joinerRouterRloc));
501 
502     message = Get<Tmf::Agent>().NewPriorityNonConfirmablePostMessage(kUriRelayTx);
503     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
504 
505     SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
506                                                           aMessage.GetLength() - aMessage.GetOffset()));
507 
508     messageInfo.SetSockAddrToRlocPeerAddrTo(joinerRouterRloc);
509     messageInfo.SetSockPortToTmf();
510 
511     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo));
512 
513     LogInfo("Sent to joiner router request on RelayTx (c/tx)");
514 
515 exit:
516     FreeMessageOnError(message, error);
517     LogError("send to joiner router request RelayTx (c/tx)", error);
518 }
519 
ForwardToLeader(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo,Uri aUri)520 Error BorderAgent::ForwardToLeader(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, Uri aUri)
521 {
522     Error                    error = kErrorNone;
523     OwnedPtr<ForwardContext> forwardContext;
524     Tmf::MessageInfo         messageInfo(GetInstance());
525     Coap::Message           *message  = nullptr;
526     bool                     petition = false;
527     bool                     separate = false;
528 
529     VerifyOrExit(mState != kStateStopped);
530 
531     switch (aUri)
532     {
533     case kUriLeaderPetition:
534         petition = true;
535         separate = true;
536         break;
537     case kUriLeaderKeepAlive:
538         separate = true;
539         break;
540     default:
541         break;
542     }
543 
544     if (separate)
545     {
546         SuccessOrExit(error = Get<Tmf::SecureAgent>().SendAck(aMessage, aMessageInfo));
547     }
548 
549     forwardContext.Reset(ForwardContext::AllocateAndInit(GetInstance(), aMessage, petition, separate));
550     VerifyOrExit(!forwardContext.IsNull(), error = kErrorNoBufs);
551 
552     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(aUri);
553     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
554 
555     SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, aMessage.GetOffset(),
556                                                           aMessage.GetLength() - aMessage.GetOffset()));
557 
558     SuccessOrExit(error = messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
559     messageInfo.SetSockPortToTmf();
560 
561     SuccessOrExit(error =
562                       Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleCoapResponse, forwardContext.Get()));
563 
564     // Release the ownership of `forwardContext` since `SendMessage()`
565     // will own it. We take back ownership from `HandleCoapResponse()`
566     // callback.
567 
568     forwardContext.Release();
569 
570     LogInfo("Forwarded request to leader on %s", PathForUri(aUri));
571 
572 exit:
573     LogError("forward to leader", error);
574 
575     if (error != kErrorNone)
576     {
577         FreeMessage(message);
578         SendErrorMessage(aMessage, separate, error);
579     }
580 
581     return error;
582 }
583 
HandleConnected(bool aConnected,void * aContext)584 void BorderAgent::HandleConnected(bool aConnected, void *aContext)
585 {
586     static_cast<BorderAgent *>(aContext)->HandleConnected(aConnected);
587 }
588 
HandleConnected(bool aConnected)589 void BorderAgent::HandleConnected(bool aConnected)
590 {
591     if (aConnected)
592     {
593         LogInfo("Commissioner connected");
594         mState = kStateActive;
595         mTimer.Start(kKeepAliveTimeout);
596     }
597     else
598     {
599         LogInfo("Commissioner disconnected");
600         IgnoreError(Get<Ip6::Udp>().RemoveReceiver(mUdpReceiver));
601         Get<ThreadNetif>().RemoveUnicastAddress(mCommissionerAloc);
602         mState        = kStateStarted;
603         mUdpProxyPort = 0;
604     }
605 }
606 
GetUdpPort(void) const607 uint16_t BorderAgent::GetUdpPort(void) const { return Get<Tmf::SecureAgent>().GetUdpPort(); }
608 
Start(void)609 void BorderAgent::Start(void)
610 {
611     Error error;
612     Pskc  pskc;
613 
614     VerifyOrExit(mState == kStateStopped, error = kErrorNone);
615 
616     Get<KeyManager>().GetPskc(pskc);
617     SuccessOrExit(error = Get<Tmf::SecureAgent>().Start(kUdpPort));
618     SuccessOrExit(error = Get<Tmf::SecureAgent>().SetPsk(pskc.m8, Pskc::kSize));
619 
620     pskc.Clear();
621     Get<Tmf::SecureAgent>().SetConnectedCallback(HandleConnected, this);
622 
623     mState        = kStateStarted;
624     mUdpProxyPort = 0;
625 
626     LogInfo("Border Agent start listening on port %u", GetUdpPort());
627 
628 exit:
629     LogError("start agent", error);
630 }
631 
HandleTimeout(void)632 void BorderAgent::HandleTimeout(void)
633 {
634     if (Get<Tmf::SecureAgent>().IsConnected())
635     {
636         Get<Tmf::SecureAgent>().Disconnect();
637         LogWarn("Reset commissioner session");
638     }
639 }
640 
Stop(void)641 void BorderAgent::Stop(void)
642 {
643     VerifyOrExit(mState != kStateStopped);
644 
645     mTimer.Stop();
646     Get<Tmf::SecureAgent>().Stop();
647 
648     mState        = kStateStopped;
649     mUdpProxyPort = 0;
650 
651     LogInfo("Border Agent stopped");
652 
653 exit:
654     return;
655 }
656 
657 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
LogError(const char * aActionText,Error aError)658 void BorderAgent::LogError(const char *aActionText, Error aError)
659 {
660     if (aError != kErrorNone)
661     {
662         LogWarn("Failed to %s: %s", aActionText, ErrorToString(aError));
663     }
664 }
665 #endif
666 
667 } // namespace MeshCoP
668 } // namespace ot
669 
670 #endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
671