Coverage Report

Created: 2024-02-25 06:30

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