• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 implements the child supervision feature.
32  */
33 
34 #include "child_supervision.hpp"
35 
36 #include "instance/instance.hpp"
37 
38 namespace ot {
39 
40 RegisterLogModule("ChildSupervsn");
41 
42 #if OPENTHREAD_FTD
43 
ChildSupervisor(Instance & aInstance)44 ChildSupervisor::ChildSupervisor(Instance &aInstance)
45     : InstanceLocator(aInstance)
46 {
47 }
48 
GetDestination(const Message & aMessage) const49 Child *ChildSupervisor::GetDestination(const Message &aMessage) const
50 {
51     Child   *child = nullptr;
52     uint16_t childIndex;
53 
54     VerifyOrExit(aMessage.GetType() == Message::kTypeSupervision);
55 
56     IgnoreError(aMessage.Read(0, childIndex));
57     child = Get<ChildTable>().GetChildAtIndex(childIndex);
58 
59 exit:
60     return child;
61 }
62 
SendMessage(Child & aChild)63 void ChildSupervisor::SendMessage(Child &aChild)
64 {
65     OwnedPtr<Message> messagePtr;
66     uint16_t          childIndex;
67 
68     VerifyOrExit(aChild.GetIndirectMessageCount() == 0);
69 
70     messagePtr.Reset(Get<MessagePool>().Allocate(Message::kTypeSupervision, sizeof(uint8_t)));
71     VerifyOrExit(messagePtr != nullptr);
72 
73     // Supervision message is an empty payload 15.4 data frame.
74     // The child index is stored here in the message content to allow
75     // the destination of the message to be later retrieved using
76     // `ChildSupervisor::GetDestination(message)`.
77 
78     childIndex = Get<ChildTable>().GetChildIndex(aChild);
79     SuccessOrExit(messagePtr->Append(childIndex));
80 
81     Get<MeshForwarder>().SendMessage(messagePtr.PassOwnership());
82 
83     LogInfo("Sending supervision message to child 0x%04x", aChild.GetRloc16());
84 
85 exit:
86     return;
87 }
88 
UpdateOnSend(Child & aChild)89 void ChildSupervisor::UpdateOnSend(Child &aChild) { aChild.ResetSecondsSinceLastSupervision(); }
90 
HandleTimeTick(void)91 void ChildSupervisor::HandleTimeTick(void)
92 {
93     for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
94     {
95         if (child.IsRxOnWhenIdle() || (child.GetSupervisionInterval() == 0))
96         {
97             continue;
98         }
99 
100         child.IncrementSecondsSinceLastSupervision();
101 
102         if (child.GetSecondsSinceLastSupervision() >= child.GetSupervisionInterval())
103         {
104             SendMessage(child);
105         }
106     }
107 }
108 
CheckState(void)109 void ChildSupervisor::CheckState(void)
110 {
111     // Child Supervision should run if Thread MLE operation is
112     // enabled, and there is at least one "valid" child in the
113     // child table.
114 
115     bool shouldRun = (!Get<Mle::Mle>().IsDisabled() && Get<ChildTable>().HasChildren(Child::kInStateValid));
116 
117     if (shouldRun && !Get<TimeTicker>().IsReceiverRegistered(TimeTicker::kChildSupervisor))
118     {
119         Get<TimeTicker>().RegisterReceiver(TimeTicker::kChildSupervisor);
120         LogInfo("Starting Child Supervision");
121     }
122 
123     if (!shouldRun && Get<TimeTicker>().IsReceiverRegistered(TimeTicker::kChildSupervisor))
124     {
125         Get<TimeTicker>().UnregisterReceiver(TimeTicker::kChildSupervisor);
126         LogInfo("Stopping Child Supervision");
127     }
128 }
129 
HandleNotifierEvents(Events aEvents)130 void ChildSupervisor::HandleNotifierEvents(Events aEvents)
131 {
132     if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadChildAdded | kEventThreadChildRemoved))
133     {
134         CheckState();
135     }
136 }
137 
138 #endif // #if OPENTHREAD_FTD
139 
SupervisionListener(Instance & aInstance)140 SupervisionListener::SupervisionListener(Instance &aInstance)
141     : InstanceLocator(aInstance)
142     , mTimeout(0)
143     , mInterval(kDefaultInterval)
144     , mTimer(aInstance)
145 {
146     SetTimeout(kDefaultTimeout);
147 }
148 
Start(void)149 void SupervisionListener::Start(void) { RestartTimer(); }
150 
Stop(void)151 void SupervisionListener::Stop(void) { mTimer.Stop(); }
152 
SetInterval(uint16_t aInterval)153 void SupervisionListener::SetInterval(uint16_t aInterval)
154 {
155     VerifyOrExit(mInterval != aInterval);
156 
157     LogInfo("Interval: %u -> %u", mInterval, aInterval);
158 
159     mInterval = aInterval;
160 
161     if (Get<Mle::Mle>().IsChild())
162     {
163         IgnoreError(Get<Mle::Mle>().SendChildUpdateRequestToParent());
164     }
165 
166 exit:
167     return;
168 }
169 
SetTimeout(uint16_t aTimeout)170 void SupervisionListener::SetTimeout(uint16_t aTimeout)
171 {
172     if (mTimeout != aTimeout)
173     {
174         LogInfo("Timeout: %u -> %u", mTimeout, aTimeout);
175 
176         mTimeout = aTimeout;
177         RestartTimer();
178     }
179 }
180 
UpdateOnReceive(const Mac::Address & aSourceAddress,bool aIsSecure)181 void SupervisionListener::UpdateOnReceive(const Mac::Address &aSourceAddress, bool aIsSecure)
182 {
183     // If listener is enabled and device is a child and it received a secure frame from its parent, restart the timer.
184 
185     VerifyOrExit(mTimer.IsRunning() && aIsSecure && Get<Mle::MleRouter>().IsChild() &&
186                  (Get<NeighborTable>().FindNeighbor(aSourceAddress) == &Get<Mle::MleRouter>().GetParent()));
187 
188     RestartTimer();
189 
190 exit:
191     return;
192 }
193 
RestartTimer(void)194 void SupervisionListener::RestartTimer(void)
195 {
196     if ((mTimeout != 0) && !Get<Mle::MleRouter>().IsDisabled() && !Get<MeshForwarder>().GetRxOnWhenIdle())
197     {
198         mTimer.Start(Time::SecToMsec(mTimeout));
199     }
200     else
201     {
202         mTimer.Stop();
203     }
204 }
205 
HandleTimer(void)206 void SupervisionListener::HandleTimer(void)
207 {
208     VerifyOrExit(Get<Mle::MleRouter>().IsChild() && !Get<MeshForwarder>().GetRxOnWhenIdle());
209 
210     LogWarn("Supervision timeout. No frame from parent in %u sec", mTimeout);
211     mCounter++;
212 
213     IgnoreError(Get<Mle::Mle>().SendChildUpdateRequestToParent());
214 
215 exit:
216     RestartTimer();
217 }
218 
219 } // namespace ot
220