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