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 Primary Backbone Router service management in the Thread Network.
32 */
33
34 #include "bbr_leader.hpp"
35
36 #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
37
38 #include "common/locator_getters.hpp"
39 #include "instance/instance.hpp"
40
41 namespace ot {
42 namespace BackboneRouter {
43
44 RegisterLogModule("BbrLeader");
45
Leader(Instance & aInstance)46 Leader::Leader(Instance &aInstance)
47 : InstanceLocator(aInstance)
48 {
49 Reset();
50 }
51
Reset(void)52 void Leader::Reset(void)
53 {
54 // Invalid server short address indicates no available Backbone Router service in the Thread Network.
55 mConfig.mServer16 = Mac::kShortAddrInvalid;
56
57 // Domain Prefix Length 0 indicates no available Domain Prefix in the Thread network.
58 mDomainPrefix.SetLength(0);
59 }
60
GetConfig(Config & aConfig) const61 Error Leader::GetConfig(Config &aConfig) const
62 {
63 Error error = kErrorNone;
64
65 VerifyOrExit(HasPrimary(), error = kErrorNotFound);
66
67 aConfig = mConfig;
68
69 exit:
70 return error;
71 }
72
GetServiceId(uint8_t & aServiceId) const73 Error Leader::GetServiceId(uint8_t &aServiceId) const
74 {
75 Error error = kErrorNone;
76
77 VerifyOrExit(HasPrimary(), error = kErrorNotFound);
78 error = Get<NetworkData::Service::Manager>().GetServiceId<NetworkData::Service::BackboneRouter>(
79 /* aServerStable */ true, aServiceId);
80
81 exit:
82 return error;
83 }
84
85 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
86
LogBackboneRouterPrimary(State aState,const Config & aConfig) const87 void Leader::LogBackboneRouterPrimary(State aState, const Config &aConfig) const
88 {
89 OT_UNUSED_VARIABLE(aConfig);
90
91 LogInfo("PBBR state: %s", StateToString(aState));
92
93 if (aState != kStateRemoved && aState != kStateNone)
94 {
95 LogInfo("Rloc16:0x%4x, seqno:%u, delay:%u, timeout:%lu", aConfig.mServer16, aConfig.mSequenceNumber,
96 aConfig.mReregistrationDelay, ToUlong(aConfig.mMlrTimeout));
97 }
98 }
99
StateToString(State aState)100 const char *Leader::StateToString(State aState)
101 {
102 static const char *const kStateStrings[] = {
103 "None", // (0) kStateNone
104 "Added", // (1) kStateAdded
105 "Removed", // (2) kStateRemoved
106 "Rereg triggered", // (3) kStateToTriggerRereg
107 "Refreshed", // (4) kStateRefreshed
108 "Unchanged", // (5) kStateUnchanged
109 };
110
111 static_assert(0 == kStateNone, "kStateNone value is incorrect");
112 static_assert(1 == kStateAdded, "kStateAdded value is incorrect");
113 static_assert(2 == kStateRemoved, "kStateRemoved value is incorrect");
114 static_assert(3 == kStateToTriggerRereg, "kStateToTriggerRereg value is incorrect");
115 static_assert(4 == kStateRefreshed, "kStateRefreshed value is incorrect");
116 static_assert(5 == kStateUnchanged, "kStateUnchanged value is incorrect");
117
118 return kStateStrings[aState];
119 }
120
DomainPrefixEventToString(DomainPrefixEvent aEvent)121 const char *Leader::DomainPrefixEventToString(DomainPrefixEvent aEvent)
122 {
123 static const char *const kEventStrings[] = {
124 "Added", // (0) kDomainPrefixAdded
125 "Removed", // (1) kDomainPrefixRemoved
126 "Refreshed", // (2) kDomainPrefixRefreshed
127 "Unchanged", // (3) kDomainPrefixUnchanged
128 };
129
130 static_assert(0 == kDomainPrefixAdded, "kDomainPrefixAdded value is incorrect");
131 static_assert(1 == kDomainPrefixRemoved, "kDomainPrefixRemoved value is incorrect");
132 static_assert(2 == kDomainPrefixRefreshed, "kDomainPrefixRefreshed value is incorrect");
133 static_assert(3 == kDomainPrefixUnchanged, "kDomainPrefixUnchanged value is incorrect");
134
135 return kEventStrings[aEvent];
136 }
137
138 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
139
Update(void)140 void Leader::Update(void)
141 {
142 UpdateBackboneRouterPrimary();
143 UpdateDomainPrefixConfig();
144 }
145
UpdateBackboneRouterPrimary(void)146 void Leader::UpdateBackboneRouterPrimary(void)
147 {
148 Config config;
149 State state;
150
151 Get<NetworkData::Service::Manager>().GetBackboneRouterPrimary(config);
152
153 if (config.mServer16 != mConfig.mServer16)
154 {
155 if (config.mServer16 == Mac::kShortAddrInvalid)
156 {
157 state = kStateRemoved;
158 }
159 else if (mConfig.mServer16 == Mac::kShortAddrInvalid)
160 {
161 state = kStateAdded;
162 }
163 else
164 {
165 // Short Address of PBBR changes.
166 state = kStateToTriggerRereg;
167 }
168 }
169 else if (config.mServer16 == Mac::kShortAddrInvalid)
170 {
171 // If no Primary all the time.
172 state = kStateNone;
173 }
174 else if (config.mSequenceNumber != mConfig.mSequenceNumber)
175 {
176 state = kStateToTriggerRereg;
177 }
178 else if (config.mReregistrationDelay != mConfig.mReregistrationDelay || config.mMlrTimeout != mConfig.mMlrTimeout)
179 {
180 state = kStateRefreshed;
181 }
182 else
183 {
184 state = kStateUnchanged;
185 }
186
187 // Restrain the range of MLR timeout to be always valid
188 if (config.mServer16 != Mac::kShortAddrInvalid)
189 {
190 uint32_t origTimeout = config.mMlrTimeout;
191
192 config.mMlrTimeout = Clamp(config.mMlrTimeout, kMinMlrTimeout, kMaxMlrTimeout);
193
194 if (config.mMlrTimeout != origTimeout)
195 {
196 LogNote("Leader MLR Timeout is normalized from %lu to %lu", ToUlong(origTimeout),
197 ToUlong(config.mMlrTimeout));
198 }
199 }
200
201 mConfig = config;
202 LogBackboneRouterPrimary(state, mConfig);
203
204 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
205 Get<BackboneRouter::Local>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
206 #endif
207
208 #if OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
209 Get<MlrManager>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
210 #endif
211
212 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
213 Get<DuaManager>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
214 #endif
215 }
216
UpdateDomainPrefixConfig(void)217 void Leader::UpdateDomainPrefixConfig(void)
218 {
219 NetworkData::Iterator iterator = NetworkData::kIteratorInit;
220 NetworkData::OnMeshPrefixConfig config;
221 DomainPrefixEvent event;
222 bool found = false;
223
224 while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, config) == kErrorNone)
225 {
226 if (config.mDp)
227 {
228 found = true;
229 break;
230 }
231 }
232
233 if (!found)
234 {
235 VerifyOrExit(HasDomainPrefix());
236
237 // Domain Prefix does not exist any more.
238 mDomainPrefix.Clear();
239 event = kDomainPrefixRemoved;
240 }
241 else if (config.GetPrefix() == mDomainPrefix)
242 {
243 event = kDomainPrefixUnchanged;
244 }
245 else
246 {
247 event = HasDomainPrefix() ? kDomainPrefixRefreshed : kDomainPrefixAdded;
248 mDomainPrefix = config.GetPrefix();
249 }
250
251 LogInfo("%s domain Prefix: %s", DomainPrefixEventToString(event), mDomainPrefix.ToString().AsCString());
252
253 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
254 Get<Local>().HandleDomainPrefixUpdate(event);
255 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE
256 Get<NdProxyTable>().HandleDomainPrefixUpdate(event);
257 #endif
258 #endif
259
260 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
261 Get<DuaManager>().HandleDomainPrefixUpdate(event);
262 #else
263 OT_UNUSED_VARIABLE(event);
264 #endif
265
266 exit:
267 return;
268 }
269
IsDomainUnicast(const Ip6::Address & aAddress) const270 bool Leader::IsDomainUnicast(const Ip6::Address &aAddress) const
271 {
272 return HasDomainPrefix() && aAddress.MatchesPrefix(mDomainPrefix);
273 }
274
275 } // namespace BackboneRouter
276 } // namespace ot
277
278 #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
279