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