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