1 /*
2 * Copyright (c) 2016-2017, 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 Notifier class.
32 */
33
34 #include "notifier.hpp"
35
36 #include "border_router/routing_manager.hpp"
37 #include "common/array.hpp"
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42
43 namespace ot {
44
45 RegisterLogModule("Notifier");
46
Notifier(Instance & aInstance)47 Notifier::Notifier(Instance &aInstance)
48 : InstanceLocator(aInstance)
49 , mTask(aInstance)
50 {
51 for (ExternalCallback &callback : mExternalCallbacks)
52 {
53 callback.Clear();
54 }
55 }
56
RegisterCallback(otStateChangedCallback aCallback,void * aContext)57 Error Notifier::RegisterCallback(otStateChangedCallback aCallback, void *aContext)
58 {
59 Error error = kErrorNone;
60 ExternalCallback *unusedCallback = nullptr;
61
62 VerifyOrExit(aCallback != nullptr);
63
64 for (ExternalCallback &callback : mExternalCallbacks)
65 {
66 VerifyOrExit(!callback.Matches(aCallback, aContext), error = kErrorAlready);
67
68 if (!callback.IsSet() && (unusedCallback == nullptr))
69 {
70 unusedCallback = &callback;
71 }
72 }
73
74 VerifyOrExit(unusedCallback != nullptr, error = kErrorNoBufs);
75
76 unusedCallback->Set(aCallback, aContext);
77
78 exit:
79 return error;
80 }
81
RemoveCallback(otStateChangedCallback aCallback,void * aContext)82 void Notifier::RemoveCallback(otStateChangedCallback aCallback, void *aContext)
83 {
84 VerifyOrExit(aCallback != nullptr);
85
86 for (ExternalCallback &callback : mExternalCallbacks)
87 {
88 if (callback.Matches(aCallback, aContext))
89 {
90 callback.Clear();
91 }
92 }
93
94 exit:
95 return;
96 }
97
Signal(Event aEvent)98 void Notifier::Signal(Event aEvent)
99 {
100 mEventsToSignal.Add(aEvent);
101 mSignaledEvents.Add(aEvent);
102 mTask.Post();
103 }
104
SignalIfFirst(Event aEvent)105 void Notifier::SignalIfFirst(Event aEvent)
106 {
107 if (!HasSignaled(aEvent))
108 {
109 Signal(aEvent);
110 }
111 }
112
EmitEvents(void)113 void Notifier::EmitEvents(void)
114 {
115 Events events;
116
117 VerifyOrExit(!mEventsToSignal.IsEmpty());
118
119 // Note that the callbacks may signal new events, so we create a
120 // copy of `mEventsToSignal` and then clear it.
121
122 events = mEventsToSignal;
123 mEventsToSignal.Clear();
124
125 LogEvents(events);
126
127 // Emit events to core internal modules
128
129 Get<Mle::Mle>().HandleNotifierEvents(events);
130 Get<EnergyScanServer>().HandleNotifierEvents(events);
131 #if OPENTHREAD_FTD
132 Get<MeshCoP::JoinerRouter>().HandleNotifierEvents(events);
133 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
134 Get<BackboneRouter::Manager>().HandleNotifierEvents(events);
135 #endif
136 Get<ChildSupervisor>().HandleNotifierEvents(events);
137 #if OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE || OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
138 Get<MeshCoP::DatasetUpdater>().HandleNotifierEvents(events);
139 #endif
140 #endif // OPENTHREAD_FTD
141 #if OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
142 Get<NetworkData::Notifier>().HandleNotifierEvents(events);
143 #endif
144 #if OPENTHREAD_CONFIG_ANNOUNCE_SENDER_ENABLE
145 Get<AnnounceSender>().HandleNotifierEvents(events);
146 #endif
147 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
148 Get<MeshCoP::BorderAgent>().HandleNotifierEvents(events);
149 #endif
150 #if OPENTHREAD_CONFIG_MLR_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE)
151 Get<MlrManager>().HandleNotifierEvents(events);
152 #endif
153 #if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
154 Get<DuaManager>().HandleNotifierEvents(events);
155 #endif
156 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
157 Get<Trel::Link>().HandleNotifierEvents(events);
158 #endif
159 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
160 Get<TimeSync>().HandleNotifierEvents(events);
161 #endif
162 #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
163 Get<Utils::Slaac>().HandleNotifierEvents(events);
164 #endif
165 #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
166 Get<Utils::JamDetector>().HandleNotifierEvents(events);
167 #endif
168 #if OPENTHREAD_CONFIG_OTNS_ENABLE
169 Get<Utils::Otns>().HandleNotifierEvents(events);
170 #endif
171 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
172 Get<Utils::HistoryTracker>().HandleNotifierEvents(events);
173 #endif
174 #if OPENTHREAD_ENABLE_VENDOR_EXTENSION
175 Get<Extension::ExtensionBase>().HandleNotifierEvents(events);
176 #endif
177 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
178 Get<BorderRouter::RoutingManager>().HandleNotifierEvents(events);
179 #endif
180 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE
181 Get<Srp::Client>().HandleNotifierEvents(events);
182 #endif
183 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE
184 // The `NetworkData::Publisher` is notified last (e.g., after SRP
185 // client) to allow other modules to request changes to what is
186 // being published (if needed).
187 Get<NetworkData::Publisher>().HandleNotifierEvents(events);
188 #endif
189 #if OPENTHREAD_CONFIG_LINK_METRICS_MANAGER_ENABLE
190 Get<Utils::LinkMetricsManager>().HandleNotifierEvents(events);
191 #endif
192
193 for (ExternalCallback &callback : mExternalCallbacks)
194 {
195 callback.InvokeIfSet(events.GetAsFlags());
196 }
197
198 exit:
199 return;
200 }
201
202 // LCOV_EXCL_START
203
204 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
205
LogEvents(Events aEvents) const206 void Notifier::LogEvents(Events aEvents) const
207 {
208 Events::Flags flags = aEvents.GetAsFlags();
209 bool addSpace = false;
210 bool didLog = false;
211 String<kFlagsStringBufferSize> string;
212
213 for (uint8_t bit = 0; bit < sizeof(Events::Flags) * CHAR_BIT; bit++)
214 {
215 VerifyOrExit(flags != 0);
216
217 if (flags & (1 << bit))
218 {
219 if (string.GetLength() >= kFlagsStringLineLimit)
220 {
221 LogInfo("StateChanged (0x%08lx) %s%s ...", ToUlong(aEvents.GetAsFlags()), didLog ? "... " : "[",
222 string.AsCString());
223 string.Clear();
224 didLog = true;
225 addSpace = false;
226 }
227
228 string.Append("%s%s", addSpace ? " " : "", EventToString(static_cast<Event>(1 << bit)));
229 addSpace = true;
230
231 flags ^= (1 << bit);
232 }
233 }
234
235 exit:
236 LogInfo("StateChanged (0x%08lx) %s%s]", ToUlong(aEvents.GetAsFlags()), didLog ? "... " : "[", string.AsCString());
237 }
238
EventToString(Event aEvent) const239 const char *Notifier::EventToString(Event aEvent) const
240 {
241 const char *retval = "(unknown)";
242
243 // To ensure no clipping of flag names in the logs, the returned
244 // strings from this method should have shorter length than
245 // `kMaxFlagNameLength` value.
246 static const char *const kEventStrings[] = {
247 "Ip6+", // kEventIp6AddressAdded (1 << 0)
248 "Ip6-", // kEventIp6AddressRemoved (1 << 1)
249 "Role", // kEventThreadRoleChanged (1 << 2)
250 "LLAddr", // kEventThreadLinkLocalAddrChanged (1 << 3)
251 "MLAddr", // kEventThreadMeshLocalAddrChanged (1 << 4)
252 "Rloc+", // kEventThreadRlocAdded (1 << 5)
253 "Rloc-", // kEventThreadRlocRemoved (1 << 6)
254 "PartitionId", // kEventThreadPartitionIdChanged (1 << 7)
255 "KeySeqCntr", // kEventThreadKeySeqCounterChanged (1 << 8)
256 "NetData", // kEventThreadNetdataChanged (1 << 9)
257 "Child+", // kEventThreadChildAdded (1 << 10)
258 "Child-", // kEventThreadChildRemoved (1 << 11)
259 "Ip6Mult+", // kEventIp6MulticastSubscribed (1 << 12)
260 "Ip6Mult-", // kEventIp6MulticastUnsubscribed (1 << 13)
261 "Channel", // kEventThreadChannelChanged (1 << 14)
262 "PanId", // kEventThreadPanIdChanged (1 << 15)
263 "NetName", // kEventThreadNetworkNameChanged (1 << 16)
264 "ExtPanId", // kEventThreadExtPanIdChanged (1 << 17)
265 "NetworkKey", // kEventNetworkKeyChanged (1 << 18)
266 "PSKc", // kEventPskcChanged (1 << 19)
267 "SecPolicy", // kEventSecurityPolicyChanged (1 << 20)
268 "CMNewChan", // kEventChannelManagerNewChannelChanged (1 << 21)
269 "ChanMask", // kEventSupportedChannelMaskChanged (1 << 22)
270 "CommissionerState", // kEventCommissionerStateChanged (1 << 23)
271 "NetifState", // kEventThreadNetifStateChanged (1 << 24)
272 "BbrState", // kEventThreadBackboneRouterStateChanged (1 << 25)
273 "BbrLocal", // kEventThreadBackboneRouterLocalChanged (1 << 26)
274 "JoinerState", // kEventJoinerStateChanged (1 << 27)
275 "ActDset", // kEventActiveDatasetChanged (1 << 28)
276 "PndDset", // kEventPendingDatasetChanged (1 << 29)
277 "Nat64", // kEventNat64TranslatorStateChanged (1 << 30)
278 "ParentLq", // kEventParentLinkQualityChanged (1 << 31)
279 };
280
281 for (uint8_t index = 0; index < GetArrayLength(kEventStrings); index++)
282 {
283 if (static_cast<uint32_t>(aEvent) == (1U << index))
284 {
285 retval = kEventStrings[index];
286 break;
287 }
288 }
289
290 return retval;
291 }
292
293 #else // #if OT_SHOULD_LOG_AT( OT_LOG_LEVEL_INFO)
294
LogEvents(Events) const295 void Notifier::LogEvents(Events) const {}
296
EventToString(Event) const297 const char *Notifier::EventToString(Event) const { return ""; }
298
299 #endif // #if OT_SHOULD_LOG_AT( OT_LOG_LEVEL_INFO)
300
301 // LCOV_EXCL_STOP
302
303 } // namespace ot
304