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 source address match controller.
32 */
33
34 #include "src_match_controller.hpp"
35
36 #if OPENTHREAD_FTD
37
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42 #include "instance/instance.hpp"
43 #include "mac/mac_types.hpp"
44 #include "radio/radio.hpp"
45 #include "thread/child.hpp"
46 #include "thread/mesh_forwarder.hpp"
47 #include "thread/thread_netif.hpp"
48
49 namespace ot {
50
51 RegisterLogModule("SrcMatchCtrl");
52
SourceMatchController(Instance & aInstance)53 SourceMatchController::SourceMatchController(Instance &aInstance)
54 : InstanceLocator(aInstance)
55 , mEnabled(false)
56 {
57 ClearTable();
58 }
59
IncrementMessageCount(Child & aChild)60 void SourceMatchController::IncrementMessageCount(Child &aChild)
61 {
62 if (aChild.GetIndirectMessageCount() == 0)
63 {
64 AddEntry(aChild);
65 }
66
67 aChild.IncrementIndirectMessageCount();
68 }
69
DecrementMessageCount(Child & aChild)70 void SourceMatchController::DecrementMessageCount(Child &aChild)
71 {
72 if (aChild.GetIndirectMessageCount() == 0)
73 {
74 LogWarn("DecrementMessageCount(child 0x%04x) called when already at zero count.", aChild.GetRloc16());
75 ExitNow();
76 }
77
78 aChild.DecrementIndirectMessageCount();
79
80 if (aChild.GetIndirectMessageCount() == 0)
81 {
82 ClearEntry(aChild);
83 }
84
85 exit:
86 return;
87 }
88
ResetMessageCount(Child & aChild)89 void SourceMatchController::ResetMessageCount(Child &aChild)
90 {
91 aChild.ResetIndirectMessageCount();
92 ClearEntry(aChild);
93 }
94
SetSrcMatchAsShort(Child & aChild,bool aUseShortAddress)95 void SourceMatchController::SetSrcMatchAsShort(Child &aChild, bool aUseShortAddress)
96 {
97 VerifyOrExit(aChild.IsIndirectSourceMatchShort() != aUseShortAddress);
98
99 if (aChild.GetIndirectMessageCount() > 0)
100 {
101 ClearEntry(aChild);
102 aChild.SetIndirectSourceMatchShort(aUseShortAddress);
103 AddEntry(aChild);
104 }
105 else
106 {
107 aChild.SetIndirectSourceMatchShort(aUseShortAddress);
108 }
109
110 exit:
111 return;
112 }
113
ClearTable(void)114 void SourceMatchController::ClearTable(void)
115 {
116 Get<Radio>().ClearSrcMatchShortEntries();
117 Get<Radio>().ClearSrcMatchExtEntries();
118 LogDebg("Cleared all entries");
119 }
120
Enable(bool aEnable)121 void SourceMatchController::Enable(bool aEnable)
122 {
123 mEnabled = aEnable;
124 Get<Radio>().EnableSrcMatch(mEnabled);
125 LogDebg("%sabling", mEnabled ? "En" : "Dis");
126 }
127
AddEntry(Child & aChild)128 void SourceMatchController::AddEntry(Child &aChild)
129 {
130 aChild.SetIndirectSourceMatchPending(true);
131
132 if (!IsEnabled())
133 {
134 SuccessOrExit(AddPendingEntries());
135 Enable(true);
136 }
137 else
138 {
139 VerifyOrExit(AddAddress(aChild) == kErrorNone, Enable(false));
140 aChild.SetIndirectSourceMatchPending(false);
141 }
142
143 exit:
144 return;
145 }
146
AddAddress(const Child & aChild)147 Error SourceMatchController::AddAddress(const Child &aChild)
148 {
149 Error error = kErrorNone;
150
151 if (aChild.IsIndirectSourceMatchShort())
152 {
153 error = Get<Radio>().AddSrcMatchShortEntry(aChild.GetRloc16());
154
155 LogDebg("Adding short addr: 0x%04x -- %s (%d)", aChild.GetRloc16(), ErrorToString(error), error);
156 }
157 else
158 {
159 Mac::ExtAddress address;
160
161 address.Set(aChild.GetExtAddress().m8, Mac::ExtAddress::kReverseByteOrder);
162 error = Get<Radio>().AddSrcMatchExtEntry(address);
163
164 LogDebg("Adding addr: %s -- %s (%d)", aChild.GetExtAddress().ToString().AsCString(), ErrorToString(error),
165 error);
166 }
167
168 return error;
169 }
170
ClearEntry(Child & aChild)171 void SourceMatchController::ClearEntry(Child &aChild)
172 {
173 Error error = kErrorNone;
174
175 if (aChild.IsIndirectSourceMatchPending())
176 {
177 LogDebg("Clearing pending flag for 0x%04x", aChild.GetRloc16());
178 aChild.SetIndirectSourceMatchPending(false);
179 ExitNow();
180 }
181
182 if (aChild.IsIndirectSourceMatchShort())
183 {
184 error = Get<Radio>().ClearSrcMatchShortEntry(aChild.GetRloc16());
185
186 LogDebg("Clearing short addr: 0x%04x -- %s (%d)", aChild.GetRloc16(), ErrorToString(error), error);
187 }
188 else
189 {
190 Mac::ExtAddress address;
191
192 address.Set(aChild.GetExtAddress().m8, Mac::ExtAddress::kReverseByteOrder);
193 error = Get<Radio>().ClearSrcMatchExtEntry(address);
194
195 LogDebg("Clearing addr: %s -- %s (%d)", aChild.GetExtAddress().ToString().AsCString(), ErrorToString(error),
196 error);
197 }
198
199 SuccessOrExit(error);
200
201 if (!IsEnabled())
202 {
203 SuccessOrExit(AddPendingEntries());
204 Enable(true);
205 }
206
207 exit:
208 return;
209 }
210
AddPendingEntries(void)211 Error SourceMatchController::AddPendingEntries(void)
212 {
213 Error error = kErrorNone;
214
215 for (Child &child : Get<ChildTable>().Iterate(Child::kInStateValidOrRestoring))
216 {
217 if (child.IsIndirectSourceMatchPending())
218 {
219 SuccessOrExit(error = AddAddress(child));
220 child.SetIndirectSourceMatchPending(false);
221 }
222 }
223
224 exit:
225 return error;
226 }
227
228 } // namespace ot
229
230 #endif // OPENTHREAD_FTD
231