/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 |