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