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