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