1 /*
2 * Copyright (c) 2019, 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 local Backbone Router service.
32 */
33
34 #include "bbr_local.hpp"
35
36 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
37
38 #include "common/code_utils.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/log.hpp"
41 #include "common/random.hpp"
42 #include "instance/instance.hpp"
43 #include "thread/mle_types.hpp"
44 #include "thread/thread_netif.hpp"
45
46 namespace ot {
47
48 namespace BackboneRouter {
49
50 RegisterLogModule("BbrLocal");
51
Local(Instance & aInstance)52 Local::Local(Instance &aInstance)
53 : InstanceLocator(aInstance)
54 , mIsServiceAdded(false)
55 , mState(kStateDisabled)
56 , mSequenceNumber(Random::NonCrypto::GetUint8() % 127)
57 , mRegistrationJitter(kDefaultRegistrationJitter)
58 , mReregistrationDelay(kDefaultRegistrationDelay)
59 , mRegistrationTimeout(0)
60 , mMlrTimeout(kDefaultMlrTimeout)
61 {
62 mDomainPrefixConfig.GetPrefix().SetLength(0);
63
64 // Primary Backbone Router Aloc
65 mBbrPrimaryAloc.InitAsThreadOriginMeshLocal();
66 mBbrPrimaryAloc.GetAddress().GetIid().SetToLocator(Mle::kAloc16BackboneRouterPrimary);
67
68 // All Network Backbone Routers Multicast Address.
69 mAllNetworkBackboneRouters.Clear();
70
71 mAllNetworkBackboneRouters.mFields.m8[0] = 0xff; // Multicast
72 mAllNetworkBackboneRouters.mFields.m8[1] = 0x32; // Flags = 3, Scope = 2
73 mAllNetworkBackboneRouters.mFields.m8[15] = 3; // Group ID = 3
74
75 // All Domain Backbone Routers Multicast Address.
76 mAllDomainBackboneRouters.Clear();
77
78 mAllDomainBackboneRouters.mFields.m8[0] = 0xff; // Multicast
79 mAllDomainBackboneRouters.mFields.m8[1] = 0x32; // Flags = 3, Scope = 2
80 mAllDomainBackboneRouters.mFields.m8[15] = 3; // Group ID = 3
81 }
82
SetEnabled(bool aEnable)83 void Local::SetEnabled(bool aEnable)
84 {
85 VerifyOrExit(aEnable != IsEnabled());
86
87 if (aEnable)
88 {
89 SetState(kStateSecondary);
90 AddDomainPrefixToNetworkData();
91 IgnoreError(AddService(kDecideBasedOnState));
92 }
93 else
94 {
95 RemoveDomainPrefixFromNetworkData();
96 RemoveService();
97 SetState(kStateDisabled);
98 }
99
100 exit:
101 return;
102 }
103
Reset(void)104 void Local::Reset(void)
105 {
106 VerifyOrExit(mState != kStateDisabled);
107
108 RemoveService();
109
110 if (mState == kStatePrimary)
111 {
112 // Increase sequence number when changing from Primary to Secondary.
113 IncrementSequenceNumber();
114 Get<Notifier>().Signal(kEventThreadBackboneRouterLocalChanged);
115 SetState(kStateSecondary);
116 }
117
118 exit:
119 return;
120 }
121
GetConfig(Config & aConfig) const122 void Local::GetConfig(Config &aConfig) const
123 {
124 aConfig.mSequenceNumber = mSequenceNumber;
125 aConfig.mReregistrationDelay = mReregistrationDelay;
126 aConfig.mMlrTimeout = mMlrTimeout;
127 }
128
SetConfig(const Config & aConfig)129 Error Local::SetConfig(const Config &aConfig)
130 {
131 Error error = kErrorNone;
132 bool update = false;
133
134 #if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
135 VerifyOrExit(aConfig.mMlrTimeout >= kMinMlrTimeout && aConfig.mMlrTimeout <= kMaxMlrTimeout,
136 error = kErrorInvalidArgs);
137 #endif
138 // Validate configuration according to Thread 1.2.1 Specification 5.21.3.3:
139 // "The Reregistration Delay in seconds MUST be lower than (0.5 * MLR Timeout). It MUST be at least 1."
140 VerifyOrExit(aConfig.mReregistrationDelay >= 1, error = kErrorInvalidArgs);
141 static_assert(sizeof(aConfig.mReregistrationDelay) < sizeof(aConfig.mMlrTimeout),
142 "the calculation below might overflow");
143 VerifyOrExit(aConfig.mReregistrationDelay * 2 < aConfig.mMlrTimeout, error = kErrorInvalidArgs);
144
145 if (aConfig.mReregistrationDelay != mReregistrationDelay)
146 {
147 mReregistrationDelay = aConfig.mReregistrationDelay;
148 update = true;
149 }
150
151 if (aConfig.mMlrTimeout != mMlrTimeout)
152 {
153 mMlrTimeout = aConfig.mMlrTimeout;
154 update = true;
155 }
156
157 if (aConfig.mSequenceNumber != mSequenceNumber)
158 {
159 mSequenceNumber = aConfig.mSequenceNumber;
160 update = true;
161 }
162
163 if (update)
164 {
165 Get<Notifier>().Signal(kEventThreadBackboneRouterLocalChanged);
166
167 IgnoreError(AddService(kDecideBasedOnState));
168 }
169
170 exit:
171 LogService(kActionSet, error);
172 return error;
173 }
174
AddService(RegisterMode aMode)175 Error Local::AddService(RegisterMode aMode)
176 {
177 Error error = kErrorInvalidState;
178
179 VerifyOrExit(mState != kStateDisabled && Get<Mle::Mle>().IsAttached());
180
181 switch (aMode)
182 {
183 case kDecideBasedOnState:
184 VerifyOrExit(!Get<BackboneRouter::Leader>().HasPrimary() ||
185 Get<BackboneRouter::Leader>().GetServer16() == Get<Mle::MleRouter>().GetRloc16());
186 break;
187 case kForceRegistration:
188 break;
189 }
190
191 SuccessOrExit(error = Get<NetworkData::Service::Manager>().AddBackboneRouterService(
192 mSequenceNumber, mReregistrationDelay, mMlrTimeout));
193 Get<NetworkData::Notifier>().HandleServerDataUpdated();
194
195 mIsServiceAdded = true;
196
197 exit:
198 LogService(kActionAdd, error);
199 return error;
200 }
201
RemoveService(void)202 void Local::RemoveService(void)
203 {
204 Error error;
205
206 SuccessOrExit(error = Get<NetworkData::Service::Manager>().RemoveBackboneRouterService());
207 Get<NetworkData::Notifier>().HandleServerDataUpdated();
208 mIsServiceAdded = false;
209
210 exit:
211 LogService(kActionRemove, error);
212 }
213
SetState(State aState)214 void Local::SetState(State aState)
215 {
216 VerifyOrExit(mState != aState);
217
218 switch (mState)
219 {
220 case kStateDisabled:
221 // Update All Network Backbone Routers Multicast Address for both Secondary and Primary state.
222 mAllNetworkBackboneRouters.SetMulticastNetworkPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
223 break;
224 case kStateSecondary:
225 break;
226 case kStatePrimary:
227 Get<ThreadNetif>().RemoveUnicastAddress(mBbrPrimaryAloc);
228 break;
229 }
230
231 if (aState == kStatePrimary)
232 {
233 // Add Primary Backbone Router ALOC for Primary Backbone Router.
234 mBbrPrimaryAloc.GetAddress().SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
235 Get<ThreadNetif>().AddUnicastAddress(mBbrPrimaryAloc);
236 }
237
238 mState = aState;
239
240 Get<Notifier>().Signal(kEventThreadBackboneRouterStateChanged);
241
242 exit:
243 return;
244 }
245
HandleBackboneRouterPrimaryUpdate(Leader::State aState,const Config & aConfig)246 void Local::HandleBackboneRouterPrimaryUpdate(Leader::State aState, const Config &aConfig)
247 {
248 OT_UNUSED_VARIABLE(aState);
249
250 VerifyOrExit(IsEnabled() && Get<Mle::MleRouter>().IsAttached());
251
252 // Wait some jitter before trying to Register.
253 if (aConfig.mServer16 == Mle::kInvalidRloc16)
254 {
255 mRegistrationTimeout = 1;
256
257 if (!Get<Mle::MleRouter>().IsLeader())
258 {
259 mRegistrationTimeout +=
260 Random::NonCrypto::GetUint16InRange(0, static_cast<uint16_t>(mRegistrationJitter) + 1);
261 }
262
263 Get<TimeTicker>().RegisterReceiver(TimeTicker::kBbrLocal);
264 }
265 else if (aConfig.mServer16 != Get<Mle::MleRouter>().GetRloc16())
266 {
267 Reset();
268 }
269 else if (!mIsServiceAdded)
270 {
271 // Here original PBBR restores its Backbone Router Service from Thread Network,
272 // Intentionally skips the state update as PBBR will refresh its service.
273 mSequenceNumber = aConfig.mSequenceNumber;
274 mReregistrationDelay = aConfig.mReregistrationDelay;
275 mMlrTimeout = aConfig.mMlrTimeout;
276 IncrementSequenceNumber();
277 Get<Notifier>().Signal(kEventThreadBackboneRouterLocalChanged);
278 IgnoreError(AddService(kForceRegistration));
279 }
280 else
281 {
282 SetState(kStatePrimary);
283 }
284
285 exit:
286 return;
287 }
288
HandleTimeTick(void)289 void Local::HandleTimeTick(void)
290 {
291 // Delay registration while router role transition is pending
292 // (i.e., device may soon switch from REED to router role).
293
294 VerifyOrExit(!Get<Mle::MleRouter>().IsRouterRoleTransitionPending());
295
296 if (mRegistrationTimeout > 0)
297 {
298 mRegistrationTimeout--;
299
300 if (mRegistrationTimeout == 0)
301 {
302 IgnoreError(AddService(kDecideBasedOnState));
303 }
304 }
305
306 exit:
307 if (mRegistrationTimeout == 0)
308 {
309 Get<TimeTicker>().UnregisterReceiver(TimeTicker::kBbrLocal);
310 }
311 }
312
GetDomainPrefix(NetworkData::OnMeshPrefixConfig & aConfig)313 Error Local::GetDomainPrefix(NetworkData::OnMeshPrefixConfig &aConfig)
314 {
315 Error error = kErrorNone;
316
317 VerifyOrExit(mDomainPrefixConfig.GetPrefix().GetLength() > 0, error = kErrorNotFound);
318
319 aConfig = mDomainPrefixConfig;
320
321 exit:
322 return error;
323 }
324
RemoveDomainPrefix(const Ip6::Prefix & aPrefix)325 Error Local::RemoveDomainPrefix(const Ip6::Prefix &aPrefix)
326 {
327 Error error = kErrorNone;
328
329 VerifyOrExit(aPrefix.GetLength() > 0, error = kErrorInvalidArgs);
330 VerifyOrExit(mDomainPrefixConfig.GetPrefix() == aPrefix, error = kErrorNotFound);
331
332 if (IsEnabled())
333 {
334 RemoveDomainPrefixFromNetworkData();
335 }
336
337 mDomainPrefixConfig.GetPrefix().SetLength(0);
338
339 exit:
340 return error;
341 }
342
SetDomainPrefix(const NetworkData::OnMeshPrefixConfig & aConfig)343 Error Local::SetDomainPrefix(const NetworkData::OnMeshPrefixConfig &aConfig)
344 {
345 Error error = kErrorNone;
346
347 VerifyOrExit(aConfig.IsValid(GetInstance()), error = kErrorInvalidArgs);
348
349 if (IsEnabled())
350 {
351 RemoveDomainPrefixFromNetworkData();
352 }
353
354 mDomainPrefixConfig = aConfig;
355 LogDomainPrefix(kActionSet, kErrorNone);
356
357 if (IsEnabled())
358 {
359 AddDomainPrefixToNetworkData();
360 }
361
362 exit:
363 return error;
364 }
365
ApplyNewMeshLocalPrefix(void)366 void Local::ApplyNewMeshLocalPrefix(void)
367 {
368 VerifyOrExit(IsEnabled());
369
370 Get<BackboneTmfAgent>().UnsubscribeMulticast(mAllNetworkBackboneRouters);
371 mAllNetworkBackboneRouters.SetMulticastNetworkPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
372 Get<BackboneTmfAgent>().SubscribeMulticast(mAllNetworkBackboneRouters);
373
374 exit:
375 return;
376 }
377
HandleDomainPrefixUpdate(DomainPrefixEvent aEvent)378 void Local::HandleDomainPrefixUpdate(DomainPrefixEvent aEvent)
379 {
380 if (!IsEnabled())
381 {
382 ExitNow();
383 }
384
385 if (aEvent == kDomainPrefixRemoved || aEvent == kDomainPrefixRefreshed)
386 {
387 Get<BackboneTmfAgent>().UnsubscribeMulticast(mAllDomainBackboneRouters);
388 }
389
390 if (aEvent == kDomainPrefixAdded || aEvent == kDomainPrefixRefreshed)
391 {
392 mAllDomainBackboneRouters.SetMulticastNetworkPrefix(*Get<Leader>().GetDomainPrefix());
393 Get<BackboneTmfAgent>().SubscribeMulticast(mAllDomainBackboneRouters);
394 }
395
396 if (aEvent != kDomainPrefixUnchanged)
397 {
398 mDomainPrefixCallback.InvokeIfSet(static_cast<otBackboneRouterDomainPrefixEvent>(aEvent),
399 Get<Leader>().GetDomainPrefix());
400 }
401
402 exit:
403 return;
404 }
405
RemoveDomainPrefixFromNetworkData(void)406 void Local::RemoveDomainPrefixFromNetworkData(void)
407 {
408 Error error = kErrorNotFound; // only used for logging.
409
410 if (mDomainPrefixConfig.mPrefix.mLength > 0)
411 {
412 error = Get<NetworkData::Local>().RemoveOnMeshPrefix(mDomainPrefixConfig.GetPrefix());
413 }
414
415 LogDomainPrefix(kActionRemove, error);
416 }
417
IncrementSequenceNumber(void)418 void Local::IncrementSequenceNumber(void)
419 {
420 switch (mSequenceNumber)
421 {
422 case 126:
423 case 127:
424 mSequenceNumber = 0;
425 break;
426 case 254:
427 case 255:
428 mSequenceNumber = 128;
429 break;
430 default:
431 mSequenceNumber++;
432 break;
433 }
434 }
435
AddDomainPrefixToNetworkData(void)436 void Local::AddDomainPrefixToNetworkData(void)
437 {
438 Error error = kErrorNotFound; // only used for logging.
439
440 if (mDomainPrefixConfig.GetPrefix().GetLength() > 0)
441 {
442 error = Get<NetworkData::Local>().AddOnMeshPrefix(mDomainPrefixConfig);
443 }
444
445 LogDomainPrefix(kActionAdd, error);
446 }
447
448 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
449
ActionToString(Action aAction)450 const char *Local::ActionToString(Action aAction)
451 {
452 static const char *const kActionStrings[] = {
453 "Set", // (0) kActionSet
454 "Add", // (1) kActionAdd
455 "Remove", // (2) kActionRemove
456 };
457
458 static_assert(0 == kActionSet, "kActionSet value is incorrect");
459 static_assert(1 == kActionAdd, "kActionAdd value is incorrect");
460 static_assert(2 == kActionRemove, "kActionRemove value is incorrect");
461
462 return kActionStrings[aAction];
463 }
464
LogDomainPrefix(Action aAction,Error aError)465 void Local::LogDomainPrefix(Action aAction, Error aError)
466 {
467 LogInfo("%s Domain Prefix: %s, %s", ActionToString(aAction), mDomainPrefixConfig.GetPrefix().ToString().AsCString(),
468 ErrorToString(aError));
469 }
470
LogService(Action aAction,Error aError)471 void Local::LogService(Action aAction, Error aError)
472 {
473 LogInfo("%s BBR Service: seqno (%u), delay (%us), timeout (%lus), %s", ActionToString(aAction), mSequenceNumber,
474 mReregistrationDelay, ToUlong(mMlrTimeout), ErrorToString(aError));
475 }
476
477 #endif
478
479 } // namespace BackboneRouter
480
481 } // namespace ot
482
483 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
484