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 Filter IEEE 802.15.4 frame filtering based on MAC address.
32 */
33
34 #include "mac_filter.hpp"
35
36 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
37
38 #include "common/array.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/code_utils.hpp"
41 #include "thread/neighbor.hpp"
42
43 namespace ot {
44 namespace Mac {
45
Filter(void)46 Filter::Filter(void)
47 : mMode(kModeRssInOnly)
48 , mDefaultRssIn(kFixedRssDisabled)
49 {
50 for (FilterEntry &entry : mFilterEntries)
51 {
52 entry.mFiltered = false;
53 entry.mRssIn = kFixedRssDisabled;
54 }
55 }
56
FindEntry(const ExtAddress & aExtAddress) const57 const Filter::FilterEntry *Filter::FindEntry(const ExtAddress &aExtAddress) const
58 {
59 const FilterEntry *rval = nullptr;
60
61 for (const FilterEntry &entry : mFilterEntries)
62 {
63 if (entry.IsInUse() && (aExtAddress == entry.mExtAddress))
64 {
65 ExitNow(rval = &entry);
66 }
67 }
68
69 exit:
70 return rval;
71 }
72
FindAvailableEntry(void)73 Filter::FilterEntry *Filter::FindAvailableEntry(void)
74 {
75 FilterEntry *rval = nullptr;
76
77 for (FilterEntry &entry : mFilterEntries)
78 {
79 if (!entry.IsInUse())
80 {
81 ExitNow(rval = &entry);
82 }
83 }
84
85 exit:
86 return rval;
87 }
88
AddAddress(const ExtAddress & aExtAddress)89 Error Filter::AddAddress(const ExtAddress &aExtAddress)
90 {
91 Error error = kErrorNone;
92 FilterEntry *entry = FindEntry(aExtAddress);
93
94 if (entry == nullptr)
95 {
96 VerifyOrExit((entry = FindAvailableEntry()) != nullptr, error = kErrorNoBufs);
97 entry->mExtAddress = aExtAddress;
98 }
99
100 entry->mFiltered = true;
101
102 exit:
103 return error;
104 }
105
RemoveAddress(const ExtAddress & aExtAddress)106 void Filter::RemoveAddress(const ExtAddress &aExtAddress)
107 {
108 FilterEntry *entry = FindEntry(aExtAddress);
109
110 if (entry != nullptr)
111 {
112 entry->mFiltered = false;
113 }
114 }
115
ClearAddresses(void)116 void Filter::ClearAddresses(void)
117 {
118 for (FilterEntry &entry : mFilterEntries)
119 {
120 entry.mFiltered = false;
121 }
122 }
123
GetNextAddress(Iterator & aIterator,Entry & aEntry) const124 Error Filter::GetNextAddress(Iterator &aIterator, Entry &aEntry) const
125 {
126 Error error = kErrorNotFound;
127
128 for (; aIterator < GetArrayLength(mFilterEntries); aIterator++)
129 {
130 const FilterEntry &entry = mFilterEntries[aIterator];
131
132 if (entry.mFiltered)
133 {
134 aEntry.mExtAddress = entry.mExtAddress;
135 aEntry.mRssIn = entry.mRssIn;
136 error = kErrorNone;
137 aIterator++;
138 break;
139 }
140 }
141
142 return error;
143 }
144
AddRssIn(const ExtAddress & aExtAddress,int8_t aRss)145 Error Filter::AddRssIn(const ExtAddress &aExtAddress, int8_t aRss)
146 {
147 Error error = kErrorNone;
148 FilterEntry *entry = FindEntry(aExtAddress);
149
150 if (entry == nullptr)
151 {
152 entry = FindAvailableEntry();
153 VerifyOrExit(entry != nullptr, error = kErrorNoBufs);
154
155 entry->mExtAddress = aExtAddress;
156 }
157
158 entry->mRssIn = aRss;
159
160 exit:
161 return error;
162 }
163
RemoveRssIn(const ExtAddress & aExtAddress)164 void Filter::RemoveRssIn(const ExtAddress &aExtAddress)
165 {
166 FilterEntry *entry = FindEntry(aExtAddress);
167
168 VerifyOrExit(entry != nullptr);
169
170 entry->mRssIn = kFixedRssDisabled;
171
172 exit:
173 return;
174 }
175
ClearAllRssIn(void)176 void Filter::ClearAllRssIn(void)
177 {
178 for (FilterEntry &entry : mFilterEntries)
179 {
180 entry.mRssIn = kFixedRssDisabled;
181 }
182
183 mDefaultRssIn = kFixedRssDisabled;
184 }
185
GetNextRssIn(Iterator & aIterator,Entry & aEntry) const186 Error Filter::GetNextRssIn(Iterator &aIterator, Entry &aEntry) const
187 {
188 Error error = kErrorNotFound;
189
190 for (; aIterator < GetArrayLength(mFilterEntries); aIterator++)
191 {
192 const FilterEntry &entry = mFilterEntries[aIterator];
193
194 if (entry.mRssIn != kFixedRssDisabled)
195 {
196 aEntry.mExtAddress = entry.mExtAddress;
197 aEntry.mRssIn = entry.mRssIn;
198 error = kErrorNone;
199 aIterator++;
200 ExitNow();
201 }
202 }
203
204 // Return the default RssIn at the end of list
205 if ((aIterator == GetArrayLength(mFilterEntries)) && (mDefaultRssIn != kFixedRssDisabled))
206 {
207 AsCoreType(&aEntry.mExtAddress).Fill(0xff);
208 aEntry.mRssIn = mDefaultRssIn;
209 error = kErrorNone;
210 aIterator++;
211 }
212
213 exit:
214 return error;
215 }
216
Apply(const ExtAddress & aExtAddress,int8_t & aRss) const217 Error Filter::Apply(const ExtAddress &aExtAddress, int8_t &aRss) const
218 {
219 Error error = kErrorNone;
220 const FilterEntry *entry = FindEntry(aExtAddress);
221 bool isInFilterList;
222
223 // Use the default RssIn setting for all receiving messages first.
224 aRss = mDefaultRssIn;
225
226 // In allowlist mode, entry must be present in the list, in
227 // denylist mode it must not be present.
228
229 isInFilterList = (entry != nullptr) && entry->mFiltered;
230
231 switch (mMode)
232 {
233 case kModeRssInOnly:
234 break;
235
236 case kModeAllowlist:
237 VerifyOrExit(isInFilterList, error = kErrorAddressFiltered);
238 break;
239
240 case kModeDenylist:
241 VerifyOrExit(!isInFilterList, error = kErrorAddressFiltered);
242 break;
243 }
244
245 if ((entry != nullptr) && (entry->mRssIn != kFixedRssDisabled))
246 {
247 aRss = entry->mRssIn;
248 }
249
250 exit:
251 return error;
252 }
253
ApplyToRxFrame(RxFrame & aRxFrame,const ExtAddress & aExtAddress,Neighbor * aNeighbor) const254 Error Filter::ApplyToRxFrame(RxFrame &aRxFrame, const ExtAddress &aExtAddress, Neighbor *aNeighbor) const
255 {
256 Error error;
257 int8_t fixedRss;
258
259 SuccessOrExit(error = Apply(aExtAddress, fixedRss));
260
261 VerifyOrExit(fixedRss != kFixedRssDisabled);
262
263 aRxFrame.SetRssi(fixedRss);
264
265 if (aNeighbor != nullptr)
266 {
267 // Clear the previous RSS average to ensure the fixed RSS
268 // value takes effect quickly.
269 aNeighbor->GetLinkInfo().ClearAverageRss();
270 }
271
272 exit:
273 return error;
274 }
275
276 } // namespace Mac
277 } // namespace ot
278
279 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
280