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/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/logging.hpp"
43 #include "mac/mac_types.hpp"
44 #include "radio/radio.hpp"
45 #include "thread/mesh_forwarder.hpp"
46 #include "thread/thread_netif.hpp"
47 #include "thread/topology.hpp"
48 
49 namespace ot {
50 
SourceMatchController(Instance & aInstance)51 SourceMatchController::SourceMatchController(Instance &aInstance)
52     : InstanceLocator(aInstance)
53     , mEnabled(false)
54 {
55     ClearTable();
56 }
57 
IncrementMessageCount(Child & aChild)58 void SourceMatchController::IncrementMessageCount(Child &aChild)
59 {
60     if (aChild.GetIndirectMessageCount() == 0)
61     {
62         AddEntry(aChild);
63     }
64 
65     aChild.IncrementIndirectMessageCount();
66 }
67 
DecrementMessageCount(Child & aChild)68 void SourceMatchController::DecrementMessageCount(Child &aChild)
69 {
70     if (aChild.GetIndirectMessageCount() == 0)
71     {
72         otLogWarnMac("DecrementMessageCount(child 0x%04x) called when already at zero count.", aChild.GetRloc16());
73         ExitNow();
74     }
75 
76     aChild.DecrementIndirectMessageCount();
77 
78     if (aChild.GetIndirectMessageCount() == 0)
79     {
80         ClearEntry(aChild);
81     }
82 
83 exit:
84     return;
85 }
86 
ResetMessageCount(Child & aChild)87 void SourceMatchController::ResetMessageCount(Child &aChild)
88 {
89     aChild.ResetIndirectMessageCount();
90     ClearEntry(aChild);
91 }
92 
SetSrcMatchAsShort(Child & aChild,bool aUseShortAddress)93 void SourceMatchController::SetSrcMatchAsShort(Child &aChild, bool aUseShortAddress)
94 {
95     VerifyOrExit(aChild.IsIndirectSourceMatchShort() != aUseShortAddress);
96 
97     if (aChild.GetIndirectMessageCount() > 0)
98     {
99         ClearEntry(aChild);
100         aChild.SetIndirectSourceMatchShort(aUseShortAddress);
101         AddEntry(aChild);
102     }
103     else
104     {
105         aChild.SetIndirectSourceMatchShort(aUseShortAddress);
106     }
107 
108 exit:
109     return;
110 }
111 
ClearTable(void)112 void SourceMatchController::ClearTable(void)
113 {
114     Get<Radio>().ClearSrcMatchShortEntries();
115     Get<Radio>().ClearSrcMatchExtEntries();
116     otLogDebgMac("SrcAddrMatch - Cleared all entries");
117 }
118 
Enable(bool aEnable)119 void SourceMatchController::Enable(bool aEnable)
120 {
121     mEnabled = aEnable;
122     Get<Radio>().EnableSrcMatch(mEnabled);
123     otLogDebgMac("SrcAddrMatch - %sabling", mEnabled ? "En" : "Dis");
124 }
125 
AddEntry(Child & aChild)126 void SourceMatchController::AddEntry(Child &aChild)
127 {
128     aChild.SetIndirectSourceMatchPending(true);
129 
130     if (!IsEnabled())
131     {
132         SuccessOrExit(AddPendingEntries());
133         Enable(true);
134     }
135     else
136     {
137         VerifyOrExit(AddAddress(aChild) == kErrorNone, Enable(false));
138         aChild.SetIndirectSourceMatchPending(false);
139     }
140 
141 exit:
142     return;
143 }
144 
AddAddress(const Child & aChild)145 Error SourceMatchController::AddAddress(const Child &aChild)
146 {
147     Error error = kErrorNone;
148 
149     if (aChild.IsIndirectSourceMatchShort())
150     {
151         error = Get<Radio>().AddSrcMatchShortEntry(aChild.GetRloc16());
152 
153         otLogDebgMac("SrcAddrMatch - Adding short addr: 0x%04x -- %s (%d)", aChild.GetRloc16(), ErrorToString(error),
154                      error);
155     }
156     else
157     {
158         Mac::ExtAddress address;
159 
160         address.Set(aChild.GetExtAddress().m8, Mac::ExtAddress::kReverseByteOrder);
161         error = Get<Radio>().AddSrcMatchExtEntry(address);
162 
163         otLogDebgMac("SrcAddrMatch - Adding addr: %s -- %s (%d)", aChild.GetExtAddress().ToString().AsCString(),
164                      ErrorToString(error), error);
165     }
166 
167     return error;
168 }
169 
ClearEntry(Child & aChild)170 void SourceMatchController::ClearEntry(Child &aChild)
171 {
172     Error error = kErrorNone;
173 
174     if (aChild.IsIndirectSourceMatchPending())
175     {
176         otLogDebgMac("SrcAddrMatch - Clearing pending flag for 0x%04x", aChild.GetRloc16());
177         aChild.SetIndirectSourceMatchPending(false);
178         ExitNow();
179     }
180 
181     if (aChild.IsIndirectSourceMatchShort())
182     {
183         error = Get<Radio>().ClearSrcMatchShortEntry(aChild.GetRloc16());
184 
185         otLogDebgMac("SrcAddrMatch - Clearing short addr: 0x%04x -- %s (%d)", aChild.GetRloc16(), ErrorToString(error),
186                      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         otLogDebgMac("SrcAddrMatch - Clearing addr: %s -- %s (%d)", aChild.GetExtAddress().ToString().AsCString(),
196                      ErrorToString(error), 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