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/code_utils.hpp"
39 
40 namespace ot {
41 namespace Mac {
42 
Filter(void)43 Filter::Filter(void)
44     : mMode(kModeRssInOnly)
45     , mDefaultRssIn(kFixedRssDisabled)
46 {
47     for (FilterEntry &entry : mFilterEntries)
48     {
49         entry.mFiltered = false;
50         entry.mRssIn    = kFixedRssDisabled;
51     }
52 }
53 
FindEntry(const ExtAddress & aExtAddress)54 Filter::FilterEntry *Filter::FindEntry(const ExtAddress &aExtAddress)
55 {
56     FilterEntry *rval = nullptr;
57 
58     for (FilterEntry &entry : mFilterEntries)
59     {
60         if (entry.IsInUse() && (aExtAddress == entry.mExtAddress))
61         {
62             ExitNow(rval = &entry);
63         }
64     }
65 
66 exit:
67     return rval;
68 }
69 
FindAvailableEntry(void)70 Filter::FilterEntry *Filter::FindAvailableEntry(void)
71 {
72     FilterEntry *rval = nullptr;
73 
74     for (FilterEntry &entry : mFilterEntries)
75     {
76         if (!entry.IsInUse())
77         {
78             ExitNow(rval = &entry);
79         }
80     }
81 
82 exit:
83     return rval;
84 }
85 
AddAddress(const ExtAddress & aExtAddress)86 Error Filter::AddAddress(const ExtAddress &aExtAddress)
87 {
88     Error        error = kErrorNone;
89     FilterEntry *entry = FindEntry(aExtAddress);
90 
91     if (entry == nullptr)
92     {
93         VerifyOrExit((entry = FindAvailableEntry()) != nullptr, error = kErrorNoBufs);
94         entry->mExtAddress = aExtAddress;
95     }
96 
97     entry->mFiltered = true;
98 
99 exit:
100     return error;
101 }
102 
RemoveAddress(const ExtAddress & aExtAddress)103 void Filter::RemoveAddress(const ExtAddress &aExtAddress)
104 {
105     FilterEntry *entry = FindEntry(aExtAddress);
106 
107     if (entry != nullptr)
108     {
109         entry->mFiltered = false;
110     }
111 }
112 
ClearAddresses(void)113 void Filter::ClearAddresses(void)
114 {
115     for (FilterEntry &entry : mFilterEntries)
116     {
117         entry.mFiltered = false;
118     }
119 }
120 
GetNextAddress(Iterator & aIterator,Entry & aEntry) const121 Error Filter::GetNextAddress(Iterator &aIterator, Entry &aEntry) const
122 {
123     Error error = kErrorNotFound;
124 
125     for (; aIterator < OT_ARRAY_LENGTH(mFilterEntries); aIterator++)
126     {
127         const FilterEntry &entry = mFilterEntries[aIterator];
128 
129         if (entry.mFiltered)
130         {
131             aEntry.mExtAddress = entry.mExtAddress;
132             aEntry.mRssIn      = entry.mRssIn;
133             error              = kErrorNone;
134             aIterator++;
135             break;
136         }
137     }
138 
139     return error;
140 }
141 
AddRssIn(const ExtAddress & aExtAddress,int8_t aRss)142 Error Filter::AddRssIn(const ExtAddress &aExtAddress, int8_t aRss)
143 {
144     Error        error = kErrorNone;
145     FilterEntry *entry = FindEntry(aExtAddress);
146 
147     if (entry == nullptr)
148     {
149         entry = FindAvailableEntry();
150         VerifyOrExit(entry != nullptr, error = kErrorNoBufs);
151 
152         entry->mExtAddress = aExtAddress;
153     }
154 
155     entry->mRssIn = aRss;
156 
157 exit:
158     return error;
159 }
160 
RemoveRssIn(const ExtAddress & aExtAddress)161 void Filter::RemoveRssIn(const ExtAddress &aExtAddress)
162 {
163     FilterEntry *entry = FindEntry(aExtAddress);
164 
165     VerifyOrExit(entry != nullptr);
166 
167     entry->mRssIn = kFixedRssDisabled;
168 
169 exit:
170     return;
171 }
172 
ClearAllRssIn(void)173 void Filter::ClearAllRssIn(void)
174 {
175     for (FilterEntry &entry : mFilterEntries)
176     {
177         entry.mRssIn = kFixedRssDisabled;
178     }
179 
180     mDefaultRssIn = kFixedRssDisabled;
181 }
182 
GetNextRssIn(Iterator & aIterator,Entry & aEntry)183 Error Filter::GetNextRssIn(Iterator &aIterator, Entry &aEntry)
184 {
185     Error error = kErrorNotFound;
186 
187     for (; aIterator < OT_ARRAY_LENGTH(mFilterEntries); aIterator++)
188     {
189         FilterEntry &entry = mFilterEntries[aIterator];
190 
191         if (entry.mRssIn != kFixedRssDisabled)
192         {
193             aEntry.mExtAddress = entry.mExtAddress;
194             aEntry.mRssIn      = entry.mRssIn;
195             error              = kErrorNone;
196             aIterator++;
197             ExitNow();
198         }
199     }
200 
201     // Return the default RssIn at the end of list
202     if ((aIterator == OT_ARRAY_LENGTH(mFilterEntries)) && (mDefaultRssIn != kFixedRssDisabled))
203     {
204         static_cast<ExtAddress &>(aEntry.mExtAddress).Fill(0xff);
205         aEntry.mRssIn = mDefaultRssIn;
206         error         = kErrorNone;
207         aIterator++;
208     }
209 
210 exit:
211     return error;
212 }
213 
Apply(const ExtAddress & aExtAddress,int8_t & aRss)214 Error Filter::Apply(const ExtAddress &aExtAddress, int8_t &aRss)
215 {
216     Error        error = kErrorNone;
217     FilterEntry *entry = FindEntry(aExtAddress);
218     bool         isInFilterList;
219 
220     // Use the default RssIn setting for all receiving messages first.
221     aRss = mDefaultRssIn;
222 
223     // In allowlist mode, entry must be present in the list, in
224     // denylist mode it must not be present.
225 
226     isInFilterList = (entry != nullptr) && entry->mFiltered;
227 
228     switch (mMode)
229     {
230     case kModeRssInOnly:
231         break;
232 
233     case kModeAllowlist:
234         VerifyOrExit(isInFilterList, error = kErrorAddressFiltered);
235         break;
236 
237     case kModeDenylist:
238         VerifyOrExit(!isInFilterList, error = kErrorAddressFiltered);
239         break;
240     }
241 
242     if ((entry != nullptr) && (entry->mRssIn != kFixedRssDisabled))
243     {
244         aRss = entry->mRssIn;
245     }
246 
247 exit:
248     return error;
249 }
250 
251 } // namespace Mac
252 } // namespace ot
253 
254 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
255