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