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