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