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