1 /*
2  *  Copyright (c) 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 includes definitions for child supervision feature.
32  *
33  */
34 
35 #ifndef CHILD_SUPERVISION_HPP_
36 #define CHILD_SUPERVISION_HPP_
37 
38 #include "openthread-core-config.h"
39 
40 #include <stdint.h>
41 
42 #include "common/locator.hpp"
43 #include "common/message.hpp"
44 #include "common/non_copyable.hpp"
45 #include "common/notifier.hpp"
46 #include "common/time_ticker.hpp"
47 #include "common/timer.hpp"
48 #include "mac/mac_types.hpp"
49 #include "thread/child.hpp"
50 
51 namespace ot {
52 
53 class ThreadNetif;
54 
55 /**
56  *
57  * Child supervision feature provides a mechanism for parent
58  * to ensure that a message is sent to each sleepy child within
59  * a fixed interval, namely the supervision interval. If there
60  * is no transmission to the child within the supervision
61  * interval, child supervisor enqueues and sends a supervision
62  * message (a data message with empty payload) to the child.
63  *
64  * On the child side, this is used to check the connectivity
65  * to the parent. If the child does not hear from its parent
66  * for a pre-specified timeout interval it assumes that it may
67  * be disconnected and tries to re-attach to the parent.
68  *
69  * The child supervision provides an alternative, more
70  * energy-efficient solution compared to requiring the sleepy child
71  * to periodically perform an MLE Child Update Request/Response
72  * exchange with the parent (as a way of verifying that it
73  * is still connected to the parent). The child supervision
74  * solution puts the burden of message transmissions on the
75  * parent instead of the typically more energy-constrained child.
76  *
77  * Note that most radios generate an auto-ack in hardware in
78  * response to a received frame, so the child cannot solely rely
79  * on the 15.4 acknowledgments it receives from parent as an
80  * indicator that it is still connected and is in parent's
81  * child table.
82  *
83  */
84 
85 #if OPENTHREAD_FTD
86 
87 /**
88  * Implements a child supervisor.
89  *
90  */
91 class ChildSupervisor : public InstanceLocator, private NonCopyable
92 {
93     friend class ot::Notifier;
94     friend class ot::TimeTicker;
95 
96 public:
97     /**
98      * Initializes the object.
99      *
100      * @param[in]  aInstance     A reference to the OpenThread instance.
101      *
102      */
103     explicit ChildSupervisor(Instance &aInstance);
104 
105     /**
106      * Returns the destination for a supervision message.
107      *
108      * @param[in] aMessage The message for which to get the destination.
109      *
110      * @returns  A pointer to the destination child of the message, or `nullptr` if @p aMessage is not of supervision
111      *           type.
112      *
113      */
114     Child *GetDestination(const Message &aMessage) const;
115 
116     /**
117      * Updates the supervision state for a child. It informs the child supervisor that a message was
118      * successfully sent to the child.
119      *
120      * @param[in] aChild     The child to which a message was successfully sent.
121      *
122      */
123     void UpdateOnSend(Child &aChild);
124 
125 private:
126     static constexpr uint16_t kDefaultSupervisionInterval = OPENTHREAD_CONFIG_CHILD_SUPERVISION_INTERVAL; // (seconds)
127 
128     void SendMessage(Child &aChild);
129     void CheckState(void);
130     void HandleTimeTick(void);
131     void HandleNotifierEvents(Events aEvents);
132 };
133 
134 #endif // #if OPENTHREAD_FTD
135 
136 /**
137  * Implements a child supervision listener.
138  *
139  */
140 class SupervisionListener : public InstanceLocator, private NonCopyable
141 {
142 public:
143     /**
144      * Initializes the object.
145      *
146      * @param[in]  aInstance     A reference to the OpenThread instance.
147      *
148      */
149     explicit SupervisionListener(Instance &aInstance);
150 
151     /**
152      * Starts the supervision listener operation.
153      *
154      */
155     void Start(void);
156 
157     /**
158      * Stops the supervision listener operation.
159      *
160      */
161     void Stop(void);
162 
163     /**
164      * Sets the supervision interval.
165      *
166      * @param[in] aInterval If non-zero, the desired supervision interval (in seconds), zero to disable supervision.
167      *
168      */
169     void SetInterval(uint16_t aInterval);
170 
171     /**
172      * Returns the supervision interval.
173      *
174      * @returns  The current supervision interval (seconds), or zero if supervision is disabled.
175      *
176      */
GetInterval(void) const177     uint16_t GetInterval(void) const { return mInterval; }
178 
179     /**
180      * Sets the supervision check timeout (in seconds).
181      *
182      * If the child does not hear from its parent within the given check timeout interval, it initiates the re-attach
183      * process (MLE Child Update Request/Response exchange with its parent). Setting the timeout to zero, disables the
184      * supervision check on the child.
185      *
186      * It is recommended to select a supervision check timeout value larger than the parent's child supervision
187      * interval plus the maximum time between the child's data poll transmissions.
188      *
189      * @param[in]  aTimeout   The timeout interval (in seconds), zero to disable the supervision check on the child.
190      *
191      */
192     void SetTimeout(uint16_t aTimeout);
193 
194     /**
195      * Returns the supervision check timeout interval (in seconds).
196      *
197      * @returns   The check timeout interval (in seconds) or zero if the supervision check on the child is disabled.
198      *
199      */
GetTimeout(void) const200     uint16_t GetTimeout(void) const { return mTimeout; }
201 
202     /**
203      * Returns the value of supervision check timeout failure counter.
204      *
205      * The counter tracks the number of supervision check failures on the child. It is incremented when the child does
206      * not hear from its parent within the specified check timeout interval.
207      *
208      */
GetCounter(void) const209     uint16_t GetCounter(void) const { return mCounter; }
210 
211     /**
212      * Reset the supervision check timeout failure counter.
213      *
214      */
ResetCounter(void)215     void ResetCounter(void) { mCounter = 0; }
216 
217     /**
218      * Updates the supervision listener state. It informs the listener of a received frame.
219      *
220      * @param[in]   aSourceAddress    The source MAC address of the received frame
221      * @param[in]   aIsSecure         TRUE to indicate that the received frame is secure, FALSE otherwise.
222      *
223      */
224     void UpdateOnReceive(const Mac::Address &aSourceAddress, bool aIsSecure);
225 
226 private:
227     static constexpr uint16_t kDefaultTimeout  = OPENTHREAD_CONFIG_CHILD_SUPERVISION_CHECK_TIMEOUT; // (seconds)
228     static constexpr uint16_t kDefaultInterval = OPENTHREAD_CONFIG_CHILD_SUPERVISION_INTERVAL;      // (seconds)
229 
230     void RestartTimer(void);
231     void HandleTimer(void);
232 
233     using ListenerTimer = TimerMilliIn<SupervisionListener, &SupervisionListener::HandleTimer>;
234 
235     uint16_t      mTimeout;
236     uint16_t      mInterval;
237     uint16_t      mCounter;
238     ListenerTimer mTimer;
239 };
240 
241 } // namespace ot
242 
243 #endif // CHILD_SUPERVISION_HPP_
244