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