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