| /* |
| * Copyright (c) 2017, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * This file implements Filter IEEE 802.15.4 frame filtering based on MAC address. |
| */ |
| |
| #include "mac_filter.hpp" |
| |
| #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE |
| |
| #include "common/array.hpp" |
| #include "common/as_core_type.hpp" |
| #include "common/code_utils.hpp" |
| |
| namespace ot { |
| namespace Mac { |
| |
| Filter::Filter(void) |
| : mMode(kModeRssInOnly) |
| , mDefaultRssIn(kFixedRssDisabled) |
| { |
| for (FilterEntry &entry : mFilterEntries) |
| { |
| entry.mFiltered = false; |
| entry.mRssIn = kFixedRssDisabled; |
| } |
| } |
| |
| Filter::FilterEntry *Filter::FindEntry(const ExtAddress &aExtAddress) |
| { |
| FilterEntry *rval = nullptr; |
| |
| for (FilterEntry &entry : mFilterEntries) |
| { |
| if (entry.IsInUse() && (aExtAddress == entry.mExtAddress)) |
| { |
| ExitNow(rval = &entry); |
| } |
| } |
| |
| exit: |
| return rval; |
| } |
| |
| Filter::FilterEntry *Filter::FindAvailableEntry(void) |
| { |
| FilterEntry *rval = nullptr; |
| |
| for (FilterEntry &entry : mFilterEntries) |
| { |
| if (!entry.IsInUse()) |
| { |
| ExitNow(rval = &entry); |
| } |
| } |
| |
| exit: |
| return rval; |
| } |
| |
| Error Filter::AddAddress(const ExtAddress &aExtAddress) |
| { |
| Error error = kErrorNone; |
| FilterEntry *entry = FindEntry(aExtAddress); |
| |
| if (entry == nullptr) |
| { |
| VerifyOrExit((entry = FindAvailableEntry()) != nullptr, error = kErrorNoBufs); |
| entry->mExtAddress = aExtAddress; |
| } |
| |
| entry->mFiltered = true; |
| |
| exit: |
| return error; |
| } |
| |
| void Filter::RemoveAddress(const ExtAddress &aExtAddress) |
| { |
| FilterEntry *entry = FindEntry(aExtAddress); |
| |
| if (entry != nullptr) |
| { |
| entry->mFiltered = false; |
| } |
| } |
| |
| void Filter::ClearAddresses(void) |
| { |
| for (FilterEntry &entry : mFilterEntries) |
| { |
| entry.mFiltered = false; |
| } |
| } |
| |
| Error Filter::GetNextAddress(Iterator &aIterator, Entry &aEntry) const |
| { |
| Error error = kErrorNotFound; |
| |
| for (; aIterator < GetArrayLength(mFilterEntries); aIterator++) |
| { |
| const FilterEntry &entry = mFilterEntries[aIterator]; |
| |
| if (entry.mFiltered) |
| { |
| aEntry.mExtAddress = entry.mExtAddress; |
| aEntry.mRssIn = entry.mRssIn; |
| error = kErrorNone; |
| aIterator++; |
| break; |
| } |
| } |
| |
| return error; |
| } |
| |
| Error Filter::AddRssIn(const ExtAddress &aExtAddress, int8_t aRss) |
| { |
| Error error = kErrorNone; |
| FilterEntry *entry = FindEntry(aExtAddress); |
| |
| if (entry == nullptr) |
| { |
| entry = FindAvailableEntry(); |
| VerifyOrExit(entry != nullptr, error = kErrorNoBufs); |
| |
| entry->mExtAddress = aExtAddress; |
| } |
| |
| entry->mRssIn = aRss; |
| |
| exit: |
| return error; |
| } |
| |
| void Filter::RemoveRssIn(const ExtAddress &aExtAddress) |
| { |
| FilterEntry *entry = FindEntry(aExtAddress); |
| |
| VerifyOrExit(entry != nullptr); |
| |
| entry->mRssIn = kFixedRssDisabled; |
| |
| exit: |
| return; |
| } |
| |
| void Filter::ClearAllRssIn(void) |
| { |
| for (FilterEntry &entry : mFilterEntries) |
| { |
| entry.mRssIn = kFixedRssDisabled; |
| } |
| |
| mDefaultRssIn = kFixedRssDisabled; |
| } |
| |
| Error Filter::GetNextRssIn(Iterator &aIterator, Entry &aEntry) |
| { |
| Error error = kErrorNotFound; |
| |
| for (; aIterator < GetArrayLength(mFilterEntries); aIterator++) |
| { |
| FilterEntry &entry = mFilterEntries[aIterator]; |
| |
| if (entry.mRssIn != kFixedRssDisabled) |
| { |
| aEntry.mExtAddress = entry.mExtAddress; |
| aEntry.mRssIn = entry.mRssIn; |
| error = kErrorNone; |
| aIterator++; |
| ExitNow(); |
| } |
| } |
| |
| // Return the default RssIn at the end of list |
| if ((aIterator == GetArrayLength(mFilterEntries)) && (mDefaultRssIn != kFixedRssDisabled)) |
| { |
| AsCoreType(&aEntry.mExtAddress).Fill(0xff); |
| aEntry.mRssIn = mDefaultRssIn; |
| error = kErrorNone; |
| aIterator++; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| Error Filter::Apply(const ExtAddress &aExtAddress, int8_t &aRss) |
| { |
| Error error = kErrorNone; |
| FilterEntry *entry = FindEntry(aExtAddress); |
| bool isInFilterList; |
| |
| // Use the default RssIn setting for all receiving messages first. |
| aRss = mDefaultRssIn; |
| |
| // In allowlist mode, entry must be present in the list, in |
| // denylist mode it must not be present. |
| |
| isInFilterList = (entry != nullptr) && entry->mFiltered; |
| |
| switch (mMode) |
| { |
| case kModeRssInOnly: |
| break; |
| |
| case kModeAllowlist: |
| VerifyOrExit(isInFilterList, error = kErrorAddressFiltered); |
| break; |
| |
| case kModeDenylist: |
| VerifyOrExit(!isInFilterList, error = kErrorAddressFiltered); |
| break; |
| } |
| |
| if ((entry != nullptr) && (entry->mRssIn != kFixedRssDisabled)) |
| { |
| aRss = entry->mRssIn; |
| } |
| |
| exit: |
| return error; |
| } |
| |
| } // namespace Mac |
| } // namespace ot |
| |
| #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE |