1 /*
2 * Copyright (c) 2020, 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 Backbone Router management.
32 */
33
34 #include "bbr_manager.hpp"
35
36 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
37
38 #include "common/code_utils.hpp"
39 #include "common/instance.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/logging.hpp"
42 #include "common/random.hpp"
43 #include "thread/mle_types.hpp"
44 #include "thread/thread_netif.hpp"
45 #include "thread/thread_tlvs.hpp"
46 #include "thread/uri_paths.hpp"
47
48 namespace ot {
49
50 namespace BackboneRouter {
51
Manager(Instance & aInstance)52 Manager::Manager(Instance &aInstance)
53 : InstanceLocator(aInstance)
54 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
55 , mMulticastListenerRegistration(UriPath::kMlr, Manager::HandleMulticastListenerRegistration, this)
56 #endif
57 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
58 , mDuaRegistration(UriPath::kDuaRegistrationRequest, Manager::HandleDuaRegistration, this)
59 , mBackboneQuery(UriPath::kBackboneQuery, Manager::HandleBackboneQuery, this)
60 , mBackboneAnswer(UriPath::kBackboneAnswer, Manager::HandleBackboneAnswer, this)
61 , mNdProxyTable(aInstance)
62 #endif
63 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
64 , mMulticastListenersTable(aInstance)
65 #endif
66 , mTimer(aInstance, Manager::HandleTimer)
67 , mBackboneTmfAgent(aInstance)
68 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
69 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
70 , mDuaResponseStatus(ThreadStatusTlv::kDuaSuccess)
71 #endif
72 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
73 , mMlrResponseStatus(ThreadStatusTlv::kMlrSuccess)
74 #endif
75 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
76 , mDuaResponseIsSpecified(false)
77 #endif
78 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
79 , mMlrResponseIsSpecified(false)
80 #endif
81 #endif
82 {
83 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
84 mBackboneTmfAgent.AddResource(mBackboneQuery);
85 mBackboneTmfAgent.AddResource(mBackboneAnswer);
86 #endif
87 }
88
HandleNotifierEvents(Events aEvents)89 void Manager::HandleNotifierEvents(Events aEvents)
90 {
91 Error error;
92
93 if (aEvents.Contains(kEventThreadBackboneRouterStateChanged))
94 {
95 if (Get<Local>().GetState() == OT_BACKBONE_ROUTER_STATE_DISABLED)
96 {
97 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
98 Get<Tmf::Agent>().RemoveResource(mMulticastListenerRegistration);
99 mMulticastListenersTable.Clear();
100 #endif
101 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
102 Get<Tmf::Agent>().RemoveResource(mDuaRegistration);
103 #endif
104 mTimer.Stop();
105
106 error = mBackboneTmfAgent.Stop();
107
108 if (error != kErrorNone)
109 {
110 otLogWarnBbr("Stop Backbone TMF agent: %s", ErrorToString(error));
111 }
112 else
113 {
114 otLogInfoBbr("Stop Backbone TMF agent: %s", ErrorToString(error));
115 }
116 }
117 else
118 {
119 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
120 Get<Tmf::Agent>().AddResource(mMulticastListenerRegistration);
121 #endif
122 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
123 Get<Tmf::Agent>().AddResource(mDuaRegistration);
124 #endif
125 if (!mTimer.IsRunning())
126 {
127 mTimer.Start(kTimerInterval);
128 }
129
130 error = mBackboneTmfAgent.Start();
131
132 otLogResultBbr(error, "Start Backbone TMF agent");
133 }
134 }
135 }
136
HandleTimer(Timer & aTimer)137 void Manager::HandleTimer(Timer &aTimer)
138 {
139 aTimer.Get<Manager>().HandleTimer();
140 }
141
HandleTimer(void)142 void Manager::HandleTimer(void)
143 {
144 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
145 mMulticastListenersTable.Expire();
146 #endif
147
148 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
149 mNdProxyTable.HandleTimer();
150 #endif
151
152 mTimer.Start(kTimerInterval);
153 }
154
155 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
HandleMulticastListenerRegistration(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)156 void Manager::HandleMulticastListenerRegistration(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
157 {
158 Error error = kErrorNone;
159 bool isPrimary = Get<Local>().IsPrimary();
160 ThreadStatusTlv::MlrStatus status = ThreadStatusTlv::kMlrSuccess;
161 BackboneRouterConfig config;
162
163 uint16_t addressesOffset, addressesLength;
164 Ip6::Address address;
165 Ip6::Address addresses[kIp6AddressesNumMax];
166 uint8_t failedAddressNum = 0;
167 uint8_t successAddressNum = 0;
168 TimeMilli expireTime;
169 uint32_t timeout;
170 uint16_t commissionerSessionId;
171 bool hasCommissionerSessionIdTlv = false;
172 bool processTimeoutTlv = false;
173
174 VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
175
176 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
177 // Required by Test Specification 5.10.22 DUA-TC-26, only for certification purpose
178 if (mMlrResponseIsSpecified)
179 {
180 mMlrResponseIsSpecified = false;
181 ExitNow(status = mMlrResponseStatus);
182 }
183 #endif
184
185 VerifyOrExit(isPrimary, status = ThreadStatusTlv::kMlrBbrNotPrimary);
186
187 // TODO: (MLR) send configured MLR response for Reference Device
188
189 if (Tlv::Find<ThreadCommissionerSessionIdTlv>(aMessage, commissionerSessionId) == kErrorNone)
190 {
191 const MeshCoP::CommissionerSessionIdTlv *commissionerSessionIdTlv =
192 static_cast<const MeshCoP::CommissionerSessionIdTlv *>(
193 Get<NetworkData::Leader>().GetCommissioningDataSubTlv(MeshCoP::Tlv::kCommissionerSessionId));
194
195 VerifyOrExit(commissionerSessionIdTlv != nullptr &&
196 commissionerSessionIdTlv->GetCommissionerSessionId() == commissionerSessionId,
197 status = ThreadStatusTlv::kMlrGeneralFailure);
198
199 hasCommissionerSessionIdTlv = true;
200 }
201
202 processTimeoutTlv = hasCommissionerSessionIdTlv && (Tlv::Find<ThreadTimeoutTlv>(aMessage, timeout) == kErrorNone);
203
204 VerifyOrExit(Tlv::FindTlvValueOffset(aMessage, Ip6AddressesTlv::kIp6Addresses, addressesOffset, addressesLength) ==
205 kErrorNone,
206 error = kErrorParse);
207 VerifyOrExit(addressesLength % sizeof(Ip6::Address) == 0, status = ThreadStatusTlv::kMlrGeneralFailure);
208 VerifyOrExit(addressesLength / sizeof(Ip6::Address) <= kIp6AddressesNumMax,
209 status = ThreadStatusTlv::kMlrGeneralFailure);
210
211 if (!processTimeoutTlv)
212 {
213 IgnoreError(Get<Leader>().GetConfig(config));
214
215 timeout = config.mMlrTimeout;
216 }
217 else
218 {
219 VerifyOrExit(timeout < UINT32_MAX, status = ThreadStatusTlv::kMlrNoPersistent);
220
221 if (timeout != 0)
222 {
223 uint32_t origTimeout = timeout;
224
225 timeout = OT_MIN(timeout, static_cast<uint32_t>(Mle::kMlrTimeoutMax));
226 timeout = OT_MAX(timeout, static_cast<uint32_t>(Mle::kMlrTimeoutMin));
227
228 if (timeout != origTimeout)
229 {
230 otLogNoteBbr("MLR.req: MLR timeout is normalized from %u to %u", origTimeout, timeout);
231 }
232 }
233 }
234
235 expireTime = TimerMilli::GetNow() + TimeMilli::SecToMsec(timeout);
236
237 for (uint16_t offset = 0; offset < addressesLength; offset += sizeof(Ip6::Address))
238 {
239 IgnoreError(aMessage.Read(addressesOffset + offset, address));
240
241 if (timeout == 0)
242 {
243 mMulticastListenersTable.Remove(address);
244 }
245 else
246 {
247 bool failed = true;
248
249 switch (mMulticastListenersTable.Add(address, expireTime))
250 {
251 case kErrorNone:
252 failed = false;
253 break;
254 case kErrorInvalidArgs:
255 if (status == ThreadStatusTlv::kMlrSuccess)
256 {
257 status = ThreadStatusTlv::kMlrInvalid;
258 }
259 break;
260 case kErrorNoBufs:
261 if (status == ThreadStatusTlv::kMlrSuccess)
262 {
263 status = ThreadStatusTlv::kMlrNoResources;
264 }
265 break;
266 default:
267 OT_ASSERT(false);
268 }
269
270 if (failed)
271 {
272 addresses[failedAddressNum++] = address;
273 }
274 else
275 {
276 // Put successfully registered addresses at the end of `addresses`.
277 addresses[kIp6AddressesNumMax - (++successAddressNum)] = address;
278 }
279 }
280 }
281
282 exit:
283 if (error == kErrorNone)
284 {
285 SendMulticastListenerRegistrationResponse(aMessage, aMessageInfo, status, addresses, failedAddressNum);
286 }
287
288 if (successAddressNum > 0)
289 {
290 SendBackboneMulticastListenerRegistration(&addresses[kIp6AddressesNumMax - successAddressNum],
291 successAddressNum, timeout);
292 }
293 }
294
SendMulticastListenerRegistrationResponse(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo,ThreadStatusTlv::MlrStatus aStatus,Ip6::Address * aFailedAddresses,uint8_t aFailedAddressNum)295 void Manager::SendMulticastListenerRegistrationResponse(const Coap::Message & aMessage,
296 const Ip6::MessageInfo & aMessageInfo,
297 ThreadStatusTlv::MlrStatus aStatus,
298 Ip6::Address * aFailedAddresses,
299 uint8_t aFailedAddressNum)
300 {
301 Error error = kErrorNone;
302 Coap::Message *message = nullptr;
303
304 VerifyOrExit((message = Get<Tmf::Agent>().NewMessage()) != nullptr, error = kErrorNoBufs);
305
306 SuccessOrExit(message->SetDefaultResponseHeader(aMessage));
307 SuccessOrExit(message->SetPayloadMarker());
308
309 SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aStatus));
310
311 if (aFailedAddressNum > 0)
312 {
313 Ip6AddressesTlv addressesTlv;
314
315 addressesTlv.Init();
316 addressesTlv.SetLength(sizeof(Ip6::Address) * aFailedAddressNum);
317 SuccessOrExit(error = message->Append(addressesTlv));
318
319 for (uint8_t i = 0; i < aFailedAddressNum; i++)
320 {
321 SuccessOrExit(error = message->Append(aFailedAddresses[i]));
322 }
323 }
324
325 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
326
327 exit:
328 FreeMessageOnError(message, error);
329 otLogInfoBbr("Sent MLR.rsp (status=%d): %s", aStatus, ErrorToString(error));
330 }
331
SendBackboneMulticastListenerRegistration(const Ip6::Address * aAddresses,uint8_t aAddressNum,uint32_t aTimeout)332 void Manager::SendBackboneMulticastListenerRegistration(const Ip6::Address *aAddresses,
333 uint8_t aAddressNum,
334 uint32_t aTimeout)
335 {
336 Error error = kErrorNone;
337 Coap::Message * message = nullptr;
338 Ip6::MessageInfo messageInfo;
339 Ip6AddressesTlv addressesTlv;
340 BackboneTmfAgent &backboneTmf = Get<BackboneRouter::BackboneTmfAgent>();
341
342 OT_ASSERT(aAddressNum >= kIp6AddressesNumMin && aAddressNum <= kIp6AddressesNumMax);
343
344 VerifyOrExit((message = backboneTmf.NewMessage()) != nullptr, error = kErrorNoBufs);
345
346 SuccessOrExit(error = message->InitAsNonConfirmablePost(UriPath::kBackboneMlr));
347 SuccessOrExit(error = message->SetPayloadMarker());
348
349 addressesTlv.Init();
350 addressesTlv.SetLength(sizeof(Ip6::Address) * aAddressNum);
351 SuccessOrExit(error = message->Append(addressesTlv));
352 SuccessOrExit(error = message->AppendBytes(aAddresses, sizeof(Ip6::Address) * aAddressNum));
353
354 SuccessOrExit(error = Tlv::Append<ThreadTimeoutTlv>(*message, aTimeout));
355
356 messageInfo.SetPeerAddr(Get<Local>().GetAllNetworkBackboneRoutersAddress());
357 messageInfo.SetPeerPort(BackboneRouter::kBackboneUdpPort); // TODO: Provide API for configuring Backbone COAP port.
358
359 messageInfo.SetHopLimit(Mle::kDefaultBackboneHoplimit);
360 messageInfo.SetIsHostInterface(true);
361
362 SuccessOrExit(error = backboneTmf.SendMessage(*message, messageInfo));
363
364 exit:
365 FreeMessageOnError(message, error);
366 otLogInfoBbr("Sent BMLR.ntf: %s", ErrorToString(error));
367 }
368 #endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
369
370 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
HandleDuaRegistration(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)371 void Manager::HandleDuaRegistration(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
372 {
373 Error error = kErrorNone;
374 ThreadStatusTlv::DuaStatus status = ThreadStatusTlv::kDuaSuccess;
375 bool isPrimary = Get<Local>().IsPrimary();
376 uint32_t lastTransactionTime;
377 bool hasLastTransactionTime;
378 Ip6::Address target;
379 Ip6::InterfaceIdentifier meshLocalIid;
380 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
381 Coap::Code duaRespCoapCode = Coap::kCodeEmpty;
382 #endif
383
384 VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator(), error = kErrorDrop);
385 VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
386
387 SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMessage, target));
388 SuccessOrExit(error = Tlv::Find<ThreadMeshLocalEidTlv>(aMessage, meshLocalIid));
389
390 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
391 if (mDuaResponseIsSpecified && (mDuaResponseTargetMlIid.IsUnspecified() || mDuaResponseTargetMlIid == meshLocalIid))
392 {
393 mDuaResponseIsSpecified = false;
394 if (mDuaResponseStatus >= Coap::kCodeResponseMin)
395 {
396 duaRespCoapCode = static_cast<Coap::Code>(mDuaResponseStatus);
397 }
398 else
399 {
400 status = static_cast<ThreadStatusTlv::DuaStatus>(mDuaResponseStatus);
401 }
402 ExitNow();
403 }
404 #endif
405
406 VerifyOrExit(isPrimary, status = ThreadStatusTlv::kDuaNotPrimary);
407 VerifyOrExit(Get<Leader>().HasDomainPrefix(), status = ThreadStatusTlv::kDuaGeneralFailure);
408 VerifyOrExit(Get<Leader>().IsDomainUnicast(target), status = ThreadStatusTlv::kDuaInvalid);
409
410 hasLastTransactionTime = (Tlv::Find<ThreadLastTransactionTimeTlv>(aMessage, lastTransactionTime) == kErrorNone);
411
412 switch (mNdProxyTable.Register(target.GetIid(), meshLocalIid, aMessageInfo.GetPeerAddr().GetIid().GetLocator(),
413 hasLastTransactionTime ? &lastTransactionTime : nullptr))
414 {
415 case kErrorNone:
416 // TODO: update its EID-to-RLOC Map Cache based on the pair {DUA, RLOC16-source} which is gleaned from the
417 // DUA.req packet according to Thread Spec. 5.23.3.6.2
418 break;
419 case kErrorDuplicated:
420 status = ThreadStatusTlv::kDuaDuplicate;
421 break;
422 case kErrorNoBufs:
423 status = ThreadStatusTlv::kDuaNoResources;
424 break;
425 default:
426 status = ThreadStatusTlv::kDuaGeneralFailure;
427 break;
428 }
429
430 exit:
431 otLogInfoBbr("Received DUA.req on %s: %s", (isPrimary ? "PBBR" : "SBBR"), ErrorToString(error));
432
433 if (error == kErrorNone)
434 {
435 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
436 if (duaRespCoapCode != Coap::kCodeEmpty)
437 {
438 IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMessage, aMessageInfo, duaRespCoapCode));
439 }
440 else
441 #endif
442 {
443 SendDuaRegistrationResponse(aMessage, aMessageInfo, target, status);
444 }
445 }
446 }
447
SendDuaRegistrationResponse(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Ip6::Address & aTarget,ThreadStatusTlv::DuaStatus aStatus)448 void Manager::SendDuaRegistrationResponse(const Coap::Message & aMessage,
449 const Ip6::MessageInfo & aMessageInfo,
450 const Ip6::Address & aTarget,
451 ThreadStatusTlv::DuaStatus aStatus)
452 {
453 Error error = kErrorNone;
454 Coap::Message *message = nullptr;
455
456 VerifyOrExit((message = Get<Tmf::Agent>().NewMessage()) != nullptr, error = kErrorNoBufs);
457
458 SuccessOrExit(message->SetDefaultResponseHeader(aMessage));
459 SuccessOrExit(message->SetPayloadMarker());
460
461 SuccessOrExit(Tlv::Append<ThreadStatusTlv>(*message, aStatus));
462 SuccessOrExit(Tlv::Append<ThreadTargetTlv>(*message, aTarget));
463
464 SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
465
466 exit:
467 FreeMessageOnError(message, error);
468 otLogInfoBbr("Sent DUA.rsp for DUA %s, status %d %s", aTarget.ToString().AsCString(), aStatus,
469 ErrorToString(error));
470 }
471 #endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
472
473 #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
474 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
ConfigNextDuaRegistrationResponse(const Ip6::InterfaceIdentifier * aMlIid,uint8_t aStatus)475 void Manager::ConfigNextDuaRegistrationResponse(const Ip6::InterfaceIdentifier *aMlIid, uint8_t aStatus)
476 {
477 mDuaResponseIsSpecified = true;
478
479 if (aMlIid)
480 {
481 mDuaResponseTargetMlIid = *aMlIid;
482 }
483 else
484 {
485 mDuaResponseTargetMlIid.Clear();
486 }
487
488 mDuaResponseStatus = aStatus;
489 }
490 #endif
491
492 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE
ConfigNextMulticastListenerRegistrationResponse(ThreadStatusTlv::MlrStatus aStatus)493 void Manager::ConfigNextMulticastListenerRegistrationResponse(ThreadStatusTlv::MlrStatus aStatus)
494 {
495 mMlrResponseIsSpecified = true;
496 mMlrResponseStatus = aStatus;
497 }
498 #endif
499 #endif
500
501 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
GetNdProxyTable(void)502 NdProxyTable &Manager::GetNdProxyTable(void)
503 {
504 return mNdProxyTable;
505 }
506
ShouldForwardDuaToBackbone(const Ip6::Address & aAddress)507 bool Manager::ShouldForwardDuaToBackbone(const Ip6::Address &aAddress)
508 {
509 bool forwardToBackbone = false;
510 Mac::ShortAddress rloc16;
511 Error error;
512
513 VerifyOrExit(Get<Local>().IsPrimary());
514 VerifyOrExit(Get<Leader>().IsDomainUnicast(aAddress));
515
516 VerifyOrExit(!mNdProxyTable.IsRegistered(aAddress.GetIid()));
517
518 error = Get<AddressResolver>().Resolve(aAddress, rloc16, /* aAllowAddressQuery */ false);
519 VerifyOrExit(error != kErrorNone || rloc16 == Get<Mle::MleRouter>().GetRloc16());
520
521 // TODO: check if the DUA is an address of any Child?
522 forwardToBackbone = true;
523
524 exit:
525 return forwardToBackbone;
526 }
527
SendBackboneQuery(const Ip6::Address & aDua,uint16_t aRloc16)528 Error Manager::SendBackboneQuery(const Ip6::Address &aDua, uint16_t aRloc16)
529 {
530 Error error = kErrorNone;
531 Coap::Message * message = nullptr;
532 Ip6::MessageInfo messageInfo;
533
534 VerifyOrExit(Get<Local>().IsPrimary(), error = kErrorInvalidState);
535
536 VerifyOrExit((message = mBackboneTmfAgent.NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
537
538 SuccessOrExit(error = message->InitAsNonConfirmablePost(UriPath::kBackboneQuery));
539 SuccessOrExit(error = message->SetPayloadMarker());
540
541 SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, aDua));
542
543 if (aRloc16 != Mac::kShortAddrInvalid)
544 {
545 SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, aRloc16));
546 }
547
548 messageInfo.SetPeerAddr(Get<Local>().GetAllDomainBackboneRoutersAddress());
549 messageInfo.SetPeerPort(BackboneRouter::kBackboneUdpPort);
550
551 messageInfo.SetHopLimit(Mle::kDefaultBackboneHoplimit);
552 messageInfo.SetIsHostInterface(true);
553
554 error = mBackboneTmfAgent.SendMessage(*message, messageInfo);
555
556 exit:
557 otLogInfoBbr("SendBackboneQuery for %s (rloc16=%04x): %s", aDua.ToString().AsCString(), aRloc16,
558 ErrorToString(error));
559 FreeMessageOnError(message, error);
560 return error;
561 }
562
HandleBackboneQuery(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)563 void Manager::HandleBackboneQuery(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
564 {
565 static_cast<Manager *>(aContext)->HandleBackboneQuery(*static_cast<const Coap::Message *>(aMessage),
566 *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
567 }
568
HandleBackboneQuery(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)569 void Manager::HandleBackboneQuery(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
570 {
571 Error error = kErrorNone;
572 Ip6::Address dua;
573 uint16_t rloc16 = Mac::kShortAddrInvalid;
574 NdProxyTable::NdProxy *ndProxy;
575
576 VerifyOrExit(aMessageInfo.IsHostInterface(), error = kErrorDrop);
577
578 VerifyOrExit(Get<Local>().IsPrimary(), error = kErrorInvalidState);
579 VerifyOrExit(aMessage.IsNonConfirmablePostRequest(), error = kErrorParse);
580
581 SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMessage, dua));
582
583 error = Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16);
584 VerifyOrExit(error == kErrorNone || error == kErrorNotFound);
585
586 otLogInfoBbr("Received BB.qry from %s for %s (rloc16=%04x)", aMessageInfo.GetPeerAddr().ToString().AsCString(),
587 dua.ToString().AsCString(), rloc16);
588
589 ndProxy = mNdProxyTable.ResolveDua(dua);
590 VerifyOrExit(ndProxy != nullptr && !ndProxy->GetDadFlag(), error = kErrorNotFound);
591
592 error = SendBackboneAnswer(aMessageInfo, dua, rloc16, *ndProxy);
593
594 exit:
595 otLogInfoBbr("HandleBackboneQuery: %s", ErrorToString(error));
596 }
597
HandleBackboneAnswer(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)598 void Manager::HandleBackboneAnswer(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
599 {
600 static_cast<Manager *>(aContext)->HandleBackboneAnswer(*static_cast<const Coap::Message *>(aMessage),
601 *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
602 }
603
HandleBackboneAnswer(const Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)604 void Manager::HandleBackboneAnswer(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
605 {
606 Error error = kErrorNone;
607 bool proactive;
608 Ip6::Address dua;
609 Ip6::InterfaceIdentifier meshLocalIid;
610 uint16_t networkNameOffset, networkNameLength;
611 uint32_t timeSinceLastTransaction;
612 uint16_t srcRloc16 = Mac::kShortAddrInvalid;
613
614 VerifyOrExit(aMessageInfo.IsHostInterface(), error = kErrorDrop);
615
616 VerifyOrExit(Get<Local>().IsPrimary(), error = kErrorInvalidState);
617 VerifyOrExit(aMessage.IsPostRequest(), error = kErrorParse);
618
619 proactive = !aMessage.IsConfirmable();
620
621 SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMessage, dua));
622 SuccessOrExit(error = Tlv::Find<ThreadMeshLocalEidTlv>(aMessage, meshLocalIid));
623 SuccessOrExit(error = Tlv::Find<ThreadLastTransactionTimeTlv>(aMessage, timeSinceLastTransaction));
624
625 SuccessOrExit(error =
626 Tlv::FindTlvValueOffset(aMessage, ThreadTlv::kNetworkName, networkNameOffset, networkNameLength));
627
628 error = Tlv::Find<ThreadRloc16Tlv>(aMessage, srcRloc16);
629 VerifyOrExit(error == kErrorNone || error == kErrorNotFound);
630
631 if (proactive)
632 {
633 HandleProactiveBackboneNotification(dua, meshLocalIid, timeSinceLastTransaction);
634 }
635 else if (srcRloc16 == Mac::kShortAddrInvalid)
636 {
637 HandleDadBackboneAnswer(dua, meshLocalIid);
638 }
639 else
640 {
641 HandleExtendedBackboneAnswer(dua, meshLocalIid, timeSinceLastTransaction, srcRloc16);
642 }
643
644 SuccessOrExit(error = mBackboneTmfAgent.SendEmptyAck(aMessage, aMessageInfo));
645
646 exit:
647 otLogInfoBbr("HandleBackboneAnswer: %s", ErrorToString(error));
648 }
649
SendProactiveBackboneNotification(const Ip6::Address & aDua,const Ip6::InterfaceIdentifier & aMeshLocalIid,uint32_t aTimeSinceLastTransaction)650 Error Manager::SendProactiveBackboneNotification(const Ip6::Address & aDua,
651 const Ip6::InterfaceIdentifier &aMeshLocalIid,
652 uint32_t aTimeSinceLastTransaction)
653 {
654 return SendBackboneAnswer(Get<Local>().GetAllDomainBackboneRoutersAddress(), BackboneRouter::kBackboneUdpPort, aDua,
655 aMeshLocalIid, aTimeSinceLastTransaction, Mac::kShortAddrInvalid);
656 }
657
SendBackboneAnswer(const Ip6::MessageInfo & aQueryMessageInfo,const Ip6::Address & aDua,uint16_t aSrcRloc16,const NdProxyTable::NdProxy & aNdProxy)658 Error Manager::SendBackboneAnswer(const Ip6::MessageInfo & aQueryMessageInfo,
659 const Ip6::Address & aDua,
660 uint16_t aSrcRloc16,
661 const NdProxyTable::NdProxy &aNdProxy)
662 {
663 return SendBackboneAnswer(aQueryMessageInfo.GetPeerAddr(), aQueryMessageInfo.GetPeerPort(), aDua,
664 aNdProxy.GetMeshLocalIid(), aNdProxy.GetTimeSinceLastTransaction(), aSrcRloc16);
665 }
666
SendBackboneAnswer(const Ip6::Address & aDstAddr,uint16_t aDstPort,const Ip6::Address & aDua,const Ip6::InterfaceIdentifier & aMeshLocalIid,uint32_t aTimeSinceLastTransaction,uint16_t aSrcRloc16)667 Error Manager::SendBackboneAnswer(const Ip6::Address & aDstAddr,
668 uint16_t aDstPort,
669 const Ip6::Address & aDua,
670 const Ip6::InterfaceIdentifier &aMeshLocalIid,
671 uint32_t aTimeSinceLastTransaction,
672 uint16_t aSrcRloc16)
673 {
674 Error error = kErrorNone;
675 Coap::Message * message = nullptr;
676 Ip6::MessageInfo messageInfo;
677 bool proactive = aDstAddr.IsMulticast();
678
679 VerifyOrExit((message = mBackboneTmfAgent.NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
680
681 SuccessOrExit(error = message->Init(proactive ? Coap::kTypeNonConfirmable : Coap::kTypeConfirmable, Coap::kCodePost,
682 UriPath::kBackboneAnswer));
683 SuccessOrExit(error = message->SetPayloadMarker());
684
685 SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, aDua));
686
687 SuccessOrExit(error = Tlv::Append<ThreadMeshLocalEidTlv>(*message, aMeshLocalIid));
688
689 SuccessOrExit(error = Tlv::Append<ThreadLastTransactionTimeTlv>(*message, aTimeSinceLastTransaction));
690
691 {
692 const Mac::NameData nameData = Get<Mac::Mac>().GetNetworkName().GetAsData();
693
694 SuccessOrExit(error = Tlv::Append<ThreadNetworkNameTlv>(*message, nameData.GetBuffer(), nameData.GetLength()));
695 }
696
697 if (aSrcRloc16 != Mac::kShortAddrInvalid)
698 {
699 SuccessOrExit(Tlv::Append<ThreadRloc16Tlv>(*message, aSrcRloc16));
700 }
701
702 messageInfo.SetPeerAddr(aDstAddr);
703 messageInfo.SetPeerPort(aDstPort);
704
705 messageInfo.SetHopLimit(Mle::kDefaultBackboneHoplimit);
706 messageInfo.SetIsHostInterface(true);
707
708 error = mBackboneTmfAgent.SendMessage(*message, messageInfo);
709
710 exit:
711 otLogInfoBbr("Send %s for %s (rloc16=%04x): %s", proactive ? "PRO_BB.ntf" : "BB.ans", aDua.ToString().AsCString(),
712 aSrcRloc16, ErrorToString(error));
713
714 FreeMessageOnError(message, error);
715 return error;
716 }
717
HandleDadBackboneAnswer(const Ip6::Address & aDua,const Ip6::InterfaceIdentifier & aMeshLocalIid)718 void Manager::HandleDadBackboneAnswer(const Ip6::Address &aDua, const Ip6::InterfaceIdentifier &aMeshLocalIid)
719 {
720 Error error = kErrorNone;
721 NdProxyTable::NdProxy *ndProxy = mNdProxyTable.ResolveDua(aDua);
722 bool duplicate = false;
723
724 OT_UNUSED_VARIABLE(error);
725
726 VerifyOrExit(ndProxy != nullptr, error = kErrorNotFound);
727
728 duplicate = ndProxy->GetMeshLocalIid() != aMeshLocalIid;
729
730 if (duplicate)
731 {
732 Ip6::Address dest;
733
734 dest.SetToRoutingLocator(Get<Mle::MleRouter>().GetMeshLocalPrefix(), ndProxy->GetRloc16());
735 Get<AddressResolver>().SendAddressError(aDua, aMeshLocalIid, &dest);
736 }
737
738 ot::BackboneRouter::NdProxyTable::NotifyDadComplete(*ndProxy, duplicate);
739
740 exit:
741 otLogInfoBbr("HandleDadBackboneAnswer: %s, target=%s, mliid=%s, duplicate=%s", ErrorToString(error),
742 aDua.ToString().AsCString(), aMeshLocalIid.ToString().AsCString(), duplicate ? "Y" : "N");
743 }
744
HandleExtendedBackboneAnswer(const Ip6::Address & aDua,const Ip6::InterfaceIdentifier & aMeshLocalIid,uint32_t aTimeSinceLastTransaction,uint16_t aSrcRloc16)745 void Manager::HandleExtendedBackboneAnswer(const Ip6::Address & aDua,
746 const Ip6::InterfaceIdentifier &aMeshLocalIid,
747 uint32_t aTimeSinceLastTransaction,
748 uint16_t aSrcRloc16)
749 {
750 Ip6::Address dest;
751
752 dest.SetToRoutingLocator(Get<Mle::MleRouter>().GetMeshLocalPrefix(), aSrcRloc16);
753 Get<AddressResolver>().SendAddressQueryResponse(aDua, aMeshLocalIid, &aTimeSinceLastTransaction, dest);
754
755 otLogInfoBbr("HandleExtendedBackboneAnswer: target=%s, mliid=%s, LTT=%lds, rloc16=%04x",
756 aDua.ToString().AsCString(), aMeshLocalIid.ToString().AsCString(), aTimeSinceLastTransaction,
757 aSrcRloc16);
758 }
759
HandleProactiveBackboneNotification(const Ip6::Address & aDua,const Ip6::InterfaceIdentifier & aMeshLocalIid,uint32_t aTimeSinceLastTransaction)760 void Manager::HandleProactiveBackboneNotification(const Ip6::Address & aDua,
761 const Ip6::InterfaceIdentifier &aMeshLocalIid,
762 uint32_t aTimeSinceLastTransaction)
763 {
764 Error error = kErrorNone;
765 NdProxyTable::NdProxy *ndProxy = mNdProxyTable.ResolveDua(aDua);
766
767 OT_UNUSED_VARIABLE(error);
768
769 VerifyOrExit(ndProxy != nullptr, error = kErrorNotFound);
770
771 if (ndProxy->GetMeshLocalIid() == aMeshLocalIid)
772 {
773 uint32_t localTimeSinceLastTransaction = ndProxy->GetTimeSinceLastTransaction();
774
775 if (aTimeSinceLastTransaction <= localTimeSinceLastTransaction)
776 {
777 BackboneRouter::NdProxyTable::Erase(*ndProxy);
778 }
779 else
780 {
781 IgnoreError(SendProactiveBackboneNotification(aDua, ndProxy->GetMeshLocalIid(),
782 ndProxy->GetTimeSinceLastTransaction()));
783 }
784 }
785 else
786 {
787 // Duplicated address detected, send ADDR_ERR.ntf to ff03::2 in the Thread network
788 BackboneRouter::NdProxyTable::Erase(*ndProxy);
789 Get<AddressResolver>().SendAddressError(aDua, aMeshLocalIid, nullptr);
790 }
791
792 exit:
793 otLogInfoBbr("HandleProactiveBackboneNotification: %s, target=%s, mliid=%s, LTT=%lds", ErrorToString(error),
794 aDua.ToString().AsCString(), aMeshLocalIid.ToString().AsCString(), aTimeSinceLastTransaction);
795 }
796 #endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
797
798 } // namespace BackboneRouter
799
800 } // namespace ot
801
802 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
803