• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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