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 defines OpenThread Notifier class.
32  */
33 
34 #ifndef NOTIFIER_HPP_
35 #define NOTIFIER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <stdbool.h>
40 #include <stdint.h>
41 
42 #include <openthread/instance.h>
43 #include <openthread/platform/toolchain.h>
44 
45 #include "common/callback.hpp"
46 #include "common/error.hpp"
47 #include "common/locator.hpp"
48 #include "common/non_copyable.hpp"
49 #include "common/tasklet.hpp"
50 
51 namespace ot {
52 
53 /**
54  * @addtogroup core-notifier
55  *
56  * @brief
57  *   This module includes definitions for OpenThread Notifier class.
58  *
59  * @{
60  *
61  */
62 
63 /**
64  * Type represents events emitted from OpenThread Notifier.
65  *
66  */
67 enum Event : uint32_t
68 {
69     kEventIp6AddressAdded                  = OT_CHANGED_IP6_ADDRESS_ADDED,            ///< IPv6 address was added
70     kEventIp6AddressRemoved                = OT_CHANGED_IP6_ADDRESS_REMOVED,          ///< IPv6 address was removed
71     kEventThreadRoleChanged                = OT_CHANGED_THREAD_ROLE,                  ///< Role changed
72     kEventThreadLinkLocalAddrChanged       = OT_CHANGED_THREAD_LL_ADDR,               ///< Link-local address changed
73     kEventThreadMeshLocalAddrChanged       = OT_CHANGED_THREAD_ML_ADDR,               ///< Mesh-local address changed
74     kEventThreadRlocAdded                  = OT_CHANGED_THREAD_RLOC_ADDED,            ///< RLOC was added
75     kEventThreadRlocRemoved                = OT_CHANGED_THREAD_RLOC_REMOVED,          ///< RLOC was removed
76     kEventThreadPartitionIdChanged         = OT_CHANGED_THREAD_PARTITION_ID,          ///< Partition ID changed
77     kEventThreadKeySeqCounterChanged       = OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER,  ///< Key Sequence changed
78     kEventThreadNetdataChanged             = OT_CHANGED_THREAD_NETDATA,               ///< Network Data changed
79     kEventThreadChildAdded                 = OT_CHANGED_THREAD_CHILD_ADDED,           ///< Child was added
80     kEventThreadChildRemoved               = OT_CHANGED_THREAD_CHILD_REMOVED,         ///< Child was removed
81     kEventIp6MulticastSubscribed           = OT_CHANGED_IP6_MULTICAST_SUBSCRIBED,     ///< Multicast address added
82     kEventIp6MulticastUnsubscribed         = OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED,   ///< Multicast address removed
83     kEventThreadChannelChanged             = OT_CHANGED_THREAD_CHANNEL,               ///< Network channel changed
84     kEventThreadPanIdChanged               = OT_CHANGED_THREAD_PANID,                 ///< Network PAN ID changed
85     kEventThreadNetworkNameChanged         = OT_CHANGED_THREAD_NETWORK_NAME,          ///< Network name changed
86     kEventThreadExtPanIdChanged            = OT_CHANGED_THREAD_EXT_PANID,             ///< Extended PAN ID changed
87     kEventNetworkKeyChanged                = OT_CHANGED_NETWORK_KEY,                  ///< Network Key changed
88     kEventPskcChanged                      = OT_CHANGED_PSKC,                         ///< PSKc changed
89     kEventSecurityPolicyChanged            = OT_CHANGED_SECURITY_POLICY,              ///< Security Policy changed
90     kEventChannelManagerNewChannelChanged  = OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL,  ///< New Channel (channel-manager)
91     kEventSupportedChannelMaskChanged      = OT_CHANGED_SUPPORTED_CHANNEL_MASK,       ///< Channel mask changed
92     kEventCommissionerStateChanged         = OT_CHANGED_COMMISSIONER_STATE,           ///< Commissioner state changed
93     kEventThreadNetifStateChanged          = OT_CHANGED_THREAD_NETIF_STATE,           ///< Netif state changed
94     kEventThreadBackboneRouterStateChanged = OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE, ///< Backbone Router state changed
95     kEventThreadBackboneRouterLocalChanged = OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL, ///< Local Backbone Router changed
96     kEventJoinerStateChanged               = OT_CHANGED_JOINER_STATE,                 ///< Joiner state changed
97     kEventActiveDatasetChanged             = OT_CHANGED_ACTIVE_DATASET,               ///< Active Dataset changed
98     kEventPendingDatasetChanged            = OT_CHANGED_PENDING_DATASET,              ///< Pending Dataset changed
99     kEventNat64TranslatorStateChanged      = OT_CHANGED_NAT64_TRANSLATOR_STATE,       ///< Nat64Translator state changed
100     kEventParentLinkQualityChanged         = OT_CHANGED_PARENT_LINK_QUALITY,          ///< Parent link quality changed
101 };
102 
103 /**
104  * Represents a list of events.
105  *
106  */
107 class Events
108 {
109 public:
110     /**
111      * Represents a bit-field indicating a list of events (with values from `Event`)
112      *
113      */
114     typedef otChangedFlags Flags;
115 
116     /**
117      * Initializes the `Events` list (as empty).
118      *
119      */
Events(void)120     Events(void)
121         : mEventFlags(0)
122     {
123     }
124 
125     /**
126      * Clears the `Events` list.
127      *
128      */
Clear(void)129     void Clear(void) { mEventFlags = 0; }
130 
131     /**
132      * Indicates whether the `Events` list contains a given event.
133      *
134      * @param[in] aEvent  The event to check.
135      *
136      * @returns TRUE if the list contains the @p aEvent, FALSE otherwise.
137      *
138      */
Contains(Event aEvent) const139     bool Contains(Event aEvent) const { return (mEventFlags & aEvent) != 0; }
140 
141     /**
142      * Indicates whether the `Events` list contains any of a given set of events.
143      *
144      * @param[in] aEvents  The events set to check (must be a collection of `Event` constants combined using `|`).
145      *
146      * @returns TRUE if the list contains any of the @p aEvents set, FALSE otherwise.
147      *
148      */
ContainsAny(Flags aEvents) const149     bool ContainsAny(Flags aEvents) const { return (mEventFlags & aEvents) != 0; }
150 
151     /**
152      * Indicates whether the `Events` list contains all of a given set of events.
153      *
154      * @param[in] aEvents  The events set to check (must be collection of `Event` constants combined using `|`).
155      *
156      * @returns TRUE if the list contains all of the @p aEvents set, FALSE otherwise.
157      *
158      */
ContainsAll(Flags aEvents) const159     bool ContainsAll(Flags aEvents) const { return (mEventFlags & aEvents) == aEvents; }
160 
161     /**
162      * Adds a given event to the `Events` list.
163      *
164      * @param[in] aEvent  The event to add.
165      *
166      */
Add(Event aEvent)167     void Add(Event aEvent) { mEventFlags |= aEvent; }
168 
169     /**
170      * Indicates whether the `Events` list is empty.
171      *
172      * @returns TRUE if the list is empty, FALSE otherwise.
173      *
174      */
IsEmpty(void) const175     bool IsEmpty(void) const { return (mEventFlags == 0); }
176 
177     /**
178      * Gets the `Events` list as bit-field `Flags` value.
179      *
180      * @returns The list as bit-field `Flags` value.
181      *
182      */
GetAsFlags(void) const183     Flags GetAsFlags(void) const { return mEventFlags; }
184 
185 private:
186     Flags mEventFlags;
187 };
188 
189 /**
190  * Implements the OpenThread Notifier.
191  *
192  * For core internal modules, `Notifier` class emits events directly to them by invoking method `HandleNotifierEvents()`
193  * on the module instance.
194  *
195  * A `otStateChangedCallback` callback can be explicitly registered with the `Notifier`. This is mainly intended for use
196  * by external users (i.e.provided as an OpenThread public API). Max number of such callbacks that can be registered at
197  * the same time is specified by `OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS` configuration parameter.
198  *
199  */
200 class Notifier : public InstanceLocator, private NonCopyable
201 {
202 public:
203     /**
204      * Initializes a `Notifier` instance.
205      *
206      *  @param[in] aInstance     A reference to OpenThread instance.
207      *
208      */
209     explicit Notifier(Instance &aInstance);
210 
211     /**
212      * Registers an `otStateChangedCallback` handler.
213      *
214      * @param[in]  aCallback     A pointer to the handler function that is called to notify of the changes.
215      * @param[in]  aContext      A pointer to arbitrary context information.
216      *
217      * @retval kErrorNone     Successfully registered the callback.
218      * @retval kErrorAlready  The callback was already registered.
219      * @retval kErrorNoBufs   Could not add the callback due to resource constraints.
220      *
221      */
222     Error RegisterCallback(otStateChangedCallback aCallback, void *aContext);
223 
224     /**
225      * Removes/unregisters a previously registered `otStateChangedCallback` handler.
226      *
227      * @param[in]  aCallback     A pointer to the callback function pointer.
228      * @param[in]  aContext      A pointer to arbitrary context information.
229      *
230      */
231     void RemoveCallback(otStateChangedCallback aCallback, void *aContext);
232 
233     /**
234      * Schedules signaling of an event.
235      *
236      * @param[in]  aEvent     The event to signal.
237      *
238      */
239     void Signal(Event aEvent);
240 
241     /**
242      * Schedules signaling of am event only if the event has not been signaled before (first time signal).
243      *
244      * @param[in]  aEvent     The event to signal.
245      *
246      */
247     void SignalIfFirst(Event aEvent);
248 
249     /**
250      * Indicates whether or not an event signal callback is pending/scheduled.
251      *
252      * @returns TRUE if a callback is pending, FALSE otherwise.
253      *
254      */
IsPending(void) const255     bool IsPending(void) const { return !mEventsToSignal.IsEmpty(); }
256 
257     /**
258      * Indicates whether or not an event has been signaled before.
259      *
260      * @param[in]  aEvent    The event to check.
261      *
262      * @retval TRUE    The event @p aEvent have been signaled before.
263      * @retval FALSE   The event @p aEvent has not been signaled before.
264      *
265      */
HasSignaled(Event aEvent) const266     bool HasSignaled(Event aEvent) const { return mSignaledEvents.Contains(aEvent); }
267 
268     /**
269      * Updates a variable of a type `Type` with a new value and signals the given event.
270      *
271      * If the variable is already set to the same value, this method returns `kErrorAlready` and the event is
272      * signaled using `SignalIfFirst()` (i.e., signal is scheduled only if event has not been signaled before).
273      *
274      * The template `Type` should support comparison operator `==` and assignment operator `=`.
275      *
276      * @param[in,out] aVariable    A reference to the variable to update.
277      * @param[in]     aNewValue    The new value.
278      * @param[in]     aEvent       The event to signal.
279      *
280      * @retval kErrorNone      The variable was update successfully and @p aEvent was signaled.
281      * @retval kErrorAlready   The variable was already set to the same value.
282      *
283      */
Update(Type & aVariable,const Type & aNewValue,Event aEvent)284     template <typename Type> Error Update(Type &aVariable, const Type &aNewValue, Event aEvent)
285     {
286         Error error = kErrorNone;
287 
288         if (aVariable == aNewValue)
289         {
290             SignalIfFirst(aEvent);
291             error = kErrorAlready;
292         }
293         else
294         {
295             aVariable = aNewValue;
296             Signal(aEvent);
297         }
298 
299         return error;
300     }
301 
302 private:
303     static constexpr uint16_t kMaxExternalHandlers = OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS;
304 
305     // Character limit to divide the log into multiple lines in `LogChangedFlags()`.
306     static constexpr uint16_t kFlagsStringLineLimit = 70;
307 
308     // Max length for string representation of a flag by `FlagToString()`.
309     static constexpr uint8_t kMaxFlagNameLength = 25;
310 
311     static constexpr uint16_t kFlagsStringBufferSize = kFlagsStringLineLimit + kMaxFlagNameLength;
312 
313     typedef Callback<otStateChangedCallback> ExternalCallback;
314 
315     void EmitEvents(void);
316 
317     void        LogEvents(Events aEvents) const;
318     const char *EventToString(Event aEvent) const;
319 
320     using EmitEventsTask = TaskletIn<Notifier, &Notifier::EmitEvents>;
321 
322     Events           mEventsToSignal;
323     Events           mSignaledEvents;
324     EmitEventsTask   mTask;
325     ExternalCallback mExternalCallbacks[kMaxExternalHandlers];
326 };
327 
328 /**
329  * @}
330  *
331  */
332 
333 } // namespace ot
334 
335 #endif // NOTIFIER_HPP_
336