Coverage Report

Created: 2023-01-11 22:17

/src/openthread/src/core/utils/child_supervision.cpp
Line
Count
Source (jump to first uncovered line)
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 "openthread-core-config.h"
37
#include "common/code_utils.hpp"
38
#include "common/instance.hpp"
39
#include "common/locator-getters.hpp"
40
#include "common/logging.hpp"
41
#include "thread/thread_netif.hpp"
42
43
namespace ot {
44
namespace Utils {
45
46
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
47
48
#if OPENTHREAD_FTD
49
50
ChildSupervisor::ChildSupervisor(Instance &aInstance)
51
    : InstanceLocator(aInstance)
52
    , mSupervisionInterval(kDefaultSupervisionInterval)
53
    , mTimer(aInstance, &ChildSupervisor::HandleTimer, this)
54
    , mNotifierCallback(aInstance, &ChildSupervisor::HandleStateChanged, this)
55
40
{
56
40
}
57
58
void ChildSupervisor::SetSupervisionInterval(uint16_t aInterval)
59
0
{
60
0
    mSupervisionInterval = aInterval;
61
0
    CheckState();
62
0
}
63
64
Child *ChildSupervisor::GetDestination(const Message &aMessage) const
65
0
{
66
0
    Child *  child = NULL;
67
0
    uint16_t childIndex;
68
69
0
    VerifyOrExit(aMessage.GetType() == Message::kTypeSupervision);
70
71
0
    aMessage.Read(0, sizeof(childIndex), &childIndex);
72
0
    child = Get<ChildTable>().GetChildAtIndex(childIndex);
73
74
0
exit:
75
0
    return child;
76
0
}
77
78
void ChildSupervisor::SendMessage(Child &aChild)
79
0
{
80
0
    Message *message = NULL;
81
0
    uint16_t childIndex;
82
83
0
    VerifyOrExit(aChild.GetIndirectMessageCount() == 0);
84
85
0
    message = Get<MessagePool>().New(Message::kTypeSupervision, sizeof(uint8_t));
86
0
    VerifyOrExit(message != NULL);
87
88
    // Supervision message is an empty payload 15.4 data frame.
89
    // The child index is stored here in the message content to allow
90
    // the destination of the message to be later retrieved using
91
    // `ChildSupervisor::GetDestination(message)`.
92
93
0
    childIndex = Get<ChildTable>().GetChildIndex(aChild);
94
0
    SuccessOrExit(message->Append(&childIndex, sizeof(childIndex)));
95
96
0
    SuccessOrExit(Get<ThreadNetif>().SendMessage(*message));
97
0
    message = NULL;
98
99
0
    otLogInfoUtil("Sending supervision message to child 0x%04x", aChild.GetRloc16());
100
101
0
exit:
102
103
0
    if (message != NULL)
104
0
    {
105
0
        message->Free();
106
0
    }
107
0
}
108
109
void ChildSupervisor::UpdateOnSend(Child &aChild)
110
0
{
111
0
    aChild.ResetSecondsSinceLastSupervision();
112
0
}
113
114
void ChildSupervisor::HandleTimer(Timer &aTimer)
115
0
{
116
0
    aTimer.GetOwner<ChildSupervisor>().HandleTimer();
117
0
}
118
119
void ChildSupervisor::HandleTimer(void)
120
0
{
121
0
    VerifyOrExit(mSupervisionInterval != 0);
122
123
0
    for (ChildTable::Iterator iter(GetInstance(), Child::kInStateValid); !iter.IsDone(); iter++)
124
0
    {
125
0
        Child &child = *iter.GetChild();
126
127
0
        child.IncrementSecondsSinceLastSupervision();
128
129
0
        if ((child.GetSecondsSinceLastSupervision() >= mSupervisionInterval) && !child.IsRxOnWhenIdle())
130
0
        {
131
0
            SendMessage(child);
132
0
        }
133
0
    }
134
135
0
    mTimer.Start(kOneSecond);
136
137
0
exit:
138
0
    return;
139
0
}
140
141
void ChildSupervisor::CheckState(void)
142
40
{
143
40
    bool shouldRun = false;
144
145
    // Child Supervision should run if `mSupervisionInterval` is not
146
    // zero, Thread MLE operation is enabled, and there is at least one
147
    // "valid" child in the child table.
148
149
40
    shouldRun = ((mSupervisionInterval != 0) && (Get<Mle::MleRouter>().GetRole() != OT_DEVICE_ROLE_DISABLED) &&
150
40
                 Get<ChildTable>().HasChildren(Child::kInStateValid));
151
152
40
    if (shouldRun && !mTimer.IsRunning())
153
0
    {
154
0
        mTimer.Start(kOneSecond);
155
0
        otLogInfoUtil("Starting Child Supervision");
156
0
    }
157
158
40
    if (!shouldRun && mTimer.IsRunning())
159
0
    {
160
0
        mTimer.Stop();
161
0
        otLogInfoUtil("Stopping Child Supervision");
162
0
    }
163
40
}
164
165
void ChildSupervisor::HandleStateChanged(Notifier::Callback &aCallback, otChangedFlags aFlags)
166
40
{
167
40
    aCallback.GetOwner<ChildSupervisor>().HandleStateChanged(aFlags);
168
40
}
169
170
void ChildSupervisor::HandleStateChanged(otChangedFlags aFlags)
171
40
{
172
40
    if ((aFlags & (OT_CHANGED_THREAD_ROLE | OT_CHANGED_THREAD_CHILD_ADDED | OT_CHANGED_THREAD_CHILD_REMOVED)) != 0)
173
40
    {
174
40
        CheckState();
175
40
    }
176
40
}
177
178
#endif // #if OPENTHREAD_FTD
179
180
SupervisionListener::SupervisionListener(Instance &aInstance)
181
    : InstanceLocator(aInstance)
182
    , mTimeout(0)
183
    , mTimer(aInstance, &SupervisionListener::HandleTimer, this)
184
40
{
185
40
    SetTimeout(kDefaultTimeout);
186
40
}
187
188
void SupervisionListener::Start(void)
189
0
{
190
0
    RestartTimer();
191
0
}
192
193
void SupervisionListener::Stop(void)
194
80
{
195
80
    mTimer.Stop();
196
80
}
197
198
void SupervisionListener::SetTimeout(uint16_t aTimeout)
199
40
{
200
40
    if (mTimeout != aTimeout)
201
40
    {
202
40
        mTimeout = aTimeout;
203
40
        RestartTimer();
204
40
    }
205
40
}
206
207
void SupervisionListener::UpdateOnReceive(const Mac::Address &aSourceAddress, bool aIsSecure)
208
0
{
209
    // If listener is enabled and device is a child and it received a secure frame from its parent, restart the timer.
210
211
0
    VerifyOrExit(mTimer.IsRunning() && aIsSecure && (Get<Mle::MleRouter>().GetRole() == OT_DEVICE_ROLE_CHILD) &&
212
0
                 (Get<Mle::MleRouter>().GetNeighbor(aSourceAddress) == &Get<Mle::MleRouter>().GetParent()));
213
214
0
    RestartTimer();
215
216
0
exit:
217
0
    return;
218
0
}
219
220
void SupervisionListener::RestartTimer(void)
221
40
{
222
40
    if ((mTimeout != 0) && (Get<Mle::MleRouter>().GetRole() != OT_DEVICE_ROLE_DISABLED) &&
223
40
        !Get<MeshForwarder>().GetRxOnWhenIdle())
224
0
    {
225
0
        mTimer.Start(Time::SecToMsec(mTimeout));
226
0
    }
227
40
    else
228
40
    {
229
40
        mTimer.Stop();
230
40
    }
231
40
}
232
233
void SupervisionListener::HandleTimer(Timer &aTimer)
234
0
{
235
0
    aTimer.GetOwner<SupervisionListener>().HandleTimer();
236
0
}
237
238
void SupervisionListener::HandleTimer(void)
239
0
{
240
0
    VerifyOrExit((Get<Mle::MleRouter>().GetRole() == OT_DEVICE_ROLE_CHILD) && !Get<MeshForwarder>().GetRxOnWhenIdle());
241
242
0
    otLogWarnUtil("Supervision timeout. No frame from parent in %d sec", mTimeout);
243
244
0
    Get<Mle::MleRouter>().SendChildUpdateRequest();
245
246
0
exit:
247
0
    RestartTimer();
248
0
}
249
250
#endif // #if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
251
252
} // namespace Utils
253
} // namespace ot