mirror of
https://github.com/espressif/openthread.git
synced 2026-09-16 14:10:09 +00:00
[mac] enhance Mac::Filter implementation to use Array (#13584)
This commit refactors `Mac::Filter` to use `Array<Entry, kMaxEntries>` instead of a fixed-size C-style array. This enhances lookup and iteration performance by maintaining entries contiguously, avoiding iteration over empty slots up to `kMaxEntries`. It also simplifies the implementation and eliminates duplicate code by unifying entry addition/update (`AddOrUpdateEntry()`), removal (`RemoveEntry()`), and iteration (`GetNext()`) across both address filtering and RSS-In filtering. Additionally, this commit introduces comprehensive unit tests in `tests/unit/test_mac_filter.cpp` covering: - Filter modes (allowlist, denylist, RSS-In only) and transitions. - Address and RSS-In addition, updating, removal, and default RSS-In. - Entry iteration and array compaction after deletions. - Coexistence and independent lifecycles of address and RSS-In filters. - Capacity limits (`kErrorNoBufs`) and entry slot reuse.
This commit is contained in:
+98
-132
@@ -40,170 +40,93 @@
|
||||
namespace ot {
|
||||
namespace Mac {
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Filter
|
||||
|
||||
Filter::Filter(void)
|
||||
: mMode(kModeRssInOnly)
|
||||
, mDefaultRssIn(kFixedRssDisabled)
|
||||
{
|
||||
for (FilterEntry &entry : mFilterEntries)
|
||||
{
|
||||
entry.mFiltered = false;
|
||||
entry.mRssIn = kFixedRssDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
const Filter::FilterEntry *Filter::FindEntry(const ExtAddress &aExtAddress) const
|
||||
Error Filter::AddOrUpdateEntry(Type aType, const ExtAddress &aExtAddress, int8_t aRss)
|
||||
{
|
||||
const FilterEntry *rval = nullptr;
|
||||
|
||||
for (const 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);
|
||||
Error error = kErrorNone;
|
||||
Entry *entry = mEntries.FindMatching(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();
|
||||
entry = mEntries.PushBack();
|
||||
VerifyOrExit(entry != nullptr, error = kErrorNoBufs);
|
||||
|
||||
entry->mExtAddress = aExtAddress;
|
||||
entry->Init(aExtAddress);
|
||||
}
|
||||
|
||||
entry->mRssIn = aRss;
|
||||
if (aType == kAddrFilter)
|
||||
{
|
||||
entry->SetInAddrFilter(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->SetRssIn(aRss);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Filter::RemoveRssIn(const ExtAddress &aExtAddress)
|
||||
void Filter::RemoveEntry(Type aType, const ExtAddress &aExtAddress)
|
||||
{
|
||||
FilterEntry *entry = FindEntry(aExtAddress);
|
||||
Entry *entry = mEntries.FindMatching(aExtAddress);
|
||||
|
||||
VerifyOrExit(entry != nullptr);
|
||||
|
||||
entry->mRssIn = kFixedRssDisabled;
|
||||
if (aType == kAddrFilter)
|
||||
{
|
||||
entry->SetInAddrFilter(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->ClearRssIn();
|
||||
}
|
||||
|
||||
if (entry->Matches(Entry::kNotInUse))
|
||||
{
|
||||
mEntries.Remove(*entry);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Filter::ClearAllRssIn(void)
|
||||
{
|
||||
for (FilterEntry &entry : mFilterEntries)
|
||||
{
|
||||
entry.mRssIn = kFixedRssDisabled;
|
||||
}
|
||||
|
||||
mDefaultRssIn = kFixedRssDisabled;
|
||||
}
|
||||
|
||||
Error Filter::GetNextRssIn(Iterator &aIterator, Entry &aEntry) const
|
||||
Error Filter::GetNext(Type aType, Iterator &aIterator, EntryInfo &aInfo) const
|
||||
{
|
||||
Error error = kErrorNotFound;
|
||||
|
||||
for (; aIterator < GetArrayLength(mFilterEntries); aIterator++)
|
||||
for (; aIterator < mEntries.GetLength(); aIterator++)
|
||||
{
|
||||
const FilterEntry &entry = mFilterEntries[aIterator];
|
||||
const Entry &entry = mEntries[aIterator];
|
||||
|
||||
if (entry.mRssIn != kFixedRssDisabled)
|
||||
if ((aType == kAddrFilter) ? entry.IsInAddrFilter() : entry.IsInRssFilter())
|
||||
{
|
||||
aEntry.mExtAddress = entry.mExtAddress;
|
||||
aEntry.mRssIn = entry.mRssIn;
|
||||
error = kErrorNone;
|
||||
aInfo.mExtAddress = entry.GetExtAddress();
|
||||
aInfo.mRssIn = entry.GetRssIn();
|
||||
error = kErrorNone;
|
||||
aIterator++;
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrExit(aType == kRssFilter);
|
||||
|
||||
// Return the default RssIn at the end of list
|
||||
if ((aIterator == GetArrayLength(mFilterEntries)) && (mDefaultRssIn != kFixedRssDisabled))
|
||||
|
||||
VerifyOrExit(aIterator == mEntries.GetLength());
|
||||
|
||||
if (mDefaultRssIn != kFixedRssDisabled)
|
||||
{
|
||||
AsCoreType(&aEntry.mExtAddress).Fill(0xff);
|
||||
aEntry.mRssIn = mDefaultRssIn;
|
||||
error = kErrorNone;
|
||||
AsCoreType(&aInfo.mExtAddress).Fill(0xff);
|
||||
aInfo.mRssIn = mDefaultRssIn;
|
||||
error = kErrorNone;
|
||||
aIterator++;
|
||||
}
|
||||
|
||||
@@ -211,11 +134,44 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Filter::ClearAll(Type aType)
|
||||
{
|
||||
for (Entry &entry : mEntries)
|
||||
{
|
||||
if (aType == kAddrFilter)
|
||||
{
|
||||
entry.SetInAddrFilter(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.ClearRssIn();
|
||||
}
|
||||
}
|
||||
|
||||
if (aType == kRssFilter)
|
||||
{
|
||||
mDefaultRssIn = kFixedRssDisabled;
|
||||
}
|
||||
|
||||
mEntries.RemoveAllMatching(Entry::kNotInUse);
|
||||
}
|
||||
|
||||
Error Filter::AddRssIn(const ExtAddress &aExtAddress, int8_t aRss)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(aRss != kFixedRssDisabled, error = kErrorInvalidArgs);
|
||||
error = AddOrUpdateEntry(kRssFilter, aExtAddress, aRss);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Filter::Apply(const ExtAddress &aExtAddress, int8_t &aRss) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
const FilterEntry *entry = FindEntry(aExtAddress);
|
||||
bool isInFilterList;
|
||||
Error error = kErrorNone;
|
||||
const Entry *entry = mEntries.FindMatching(aExtAddress);
|
||||
bool isInAddrFilterList;
|
||||
|
||||
// Use the default RssIn setting for all receiving messages first.
|
||||
aRss = mDefaultRssIn;
|
||||
@@ -223,7 +179,7 @@ Error Filter::Apply(const ExtAddress &aExtAddress, int8_t &aRss) const
|
||||
// In allowlist mode, entry must be present in the list, in
|
||||
// denylist mode it must not be present.
|
||||
|
||||
isInFilterList = (entry != nullptr) && entry->mFiltered;
|
||||
isInAddrFilterList = (entry != nullptr) && entry->IsInAddrFilter();
|
||||
|
||||
switch (mMode)
|
||||
{
|
||||
@@ -231,17 +187,17 @@ Error Filter::Apply(const ExtAddress &aExtAddress, int8_t &aRss) const
|
||||
break;
|
||||
|
||||
case kModeAllowlist:
|
||||
VerifyOrExit(isInFilterList, error = kErrorAddressFiltered);
|
||||
VerifyOrExit(isInAddrFilterList, error = kErrorAddressFiltered);
|
||||
break;
|
||||
|
||||
case kModeDenylist:
|
||||
VerifyOrExit(!isInFilterList, error = kErrorAddressFiltered);
|
||||
VerifyOrExit(!isInAddrFilterList, error = kErrorAddressFiltered);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((entry != nullptr) && (entry->mRssIn != kFixedRssDisabled))
|
||||
if ((entry != nullptr) && entry->IsInRssFilter())
|
||||
{
|
||||
aRss = entry->mRssIn;
|
||||
aRss = entry->GetRssIn();
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -270,6 +226,16 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Filter::Entry
|
||||
|
||||
void Filter::Entry::Init(const ExtAddress &aExtAddress)
|
||||
{
|
||||
mExtAddress = aExtAddress;
|
||||
mInAddrFilter = false;
|
||||
mRssIn = kFixedRssDisabled;
|
||||
}
|
||||
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
|
||||
+63
-35
@@ -40,8 +40,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/const_cast.hpp"
|
||||
#include "common/non_copyable.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
|
||||
@@ -58,15 +58,15 @@ namespace Mac {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements Mac Filter on IEEE 802.15.4 frames.
|
||||
* Implements MAC Filter on IEEE 802.15.4 frames.
|
||||
*/
|
||||
class Filter : private NonCopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Represents a Mac Filter entry (used during iteration).
|
||||
* Represents MAC Filter entry information.
|
||||
*/
|
||||
typedef otMacFilterEntry Entry;
|
||||
typedef otMacFilterEntry EntryInfo;
|
||||
|
||||
/**
|
||||
* Represents an iterator used to iterate through filter entries.
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
typedef otMacFilterIterator Iterator;
|
||||
|
||||
/**
|
||||
* Type represents the MAC Filter mode.
|
||||
* Represents the MAC Filter mode.
|
||||
*/
|
||||
enum Mode : uint8_t
|
||||
{
|
||||
@@ -85,7 +85,8 @@ public:
|
||||
kModeDenylist = OT_MAC_FILTER_ADDRESS_MODE_DENYLIST, ///< Enable denylist address filter mode.
|
||||
};
|
||||
|
||||
static constexpr int8_t kFixedRssDisabled = OT_MAC_FILTER_FIXED_RSS_DISABLED; ///< Value when no fixed RSS is set.
|
||||
static constexpr int8_t kFixedRssDisabled = OT_MAC_FILTER_FIXED_RSS_DISABLED; ///< Value when no fixed RSS is set.
|
||||
static constexpr Iterator kIteratorInit = OT_MAC_FILTER_ITERATOR_INIT; ///< Initializer for `Iterator`.
|
||||
|
||||
/**
|
||||
* Initializes the filter.
|
||||
@@ -95,7 +96,7 @@ public:
|
||||
/**
|
||||
* Gets the MAC Filter mode.
|
||||
*
|
||||
* @returns the Filter mode.
|
||||
* @returns The Filter mode.
|
||||
*/
|
||||
Mode GetMode(void) const { return mMode; }
|
||||
|
||||
@@ -114,7 +115,10 @@ public:
|
||||
* @retval kErrorNone Successfully added @p aExtAddress to the filter.
|
||||
* @retval kErrorNoBufs No available entry exists.
|
||||
*/
|
||||
Error AddAddress(const ExtAddress &aExtAddress);
|
||||
Error AddAddress(const ExtAddress &aExtAddress)
|
||||
{
|
||||
return AddOrUpdateEntry(kAddrFilter, aExtAddress, kFixedRssDisabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an Extended Address from the filter.
|
||||
@@ -123,33 +127,34 @@ public:
|
||||
*
|
||||
* @param[in] aExtAddress A reference to the Extended Address to remove.
|
||||
*/
|
||||
void RemoveAddress(const ExtAddress &aExtAddress);
|
||||
void RemoveAddress(const ExtAddress &aExtAddress) { RemoveEntry(kAddrFilter, aExtAddress); }
|
||||
|
||||
/**
|
||||
* Clears all Extended Addresses from the filter.
|
||||
*/
|
||||
void ClearAddresses(void);
|
||||
void ClearAddresses(void) { ClearAll(kAddrFilter); }
|
||||
|
||||
/**
|
||||
* Iterates through filter entries.
|
||||
*
|
||||
* @param[in,out] aIterator A reference to the MAC filter iterator context.
|
||||
* To get the first in-use address filter, set it to OT_MAC_FILTER_ITERATOR_INIT.
|
||||
* @param[out] aEntry A reference to where the information is placed.
|
||||
* To get the first in-use address filter, set it to `kIteratorInit`.
|
||||
* @param[out] aInfo A reference to where the entry information is placed.
|
||||
*
|
||||
* @retval kErrorNone Successfully retrieved the next address filter entry.
|
||||
* @retval kErrorNotFound No subsequent entry exists.
|
||||
*/
|
||||
Error GetNextAddress(Iterator &aIterator, Entry &aEntry) const;
|
||||
Error GetNextAddress(Iterator &aIterator, EntryInfo &aInfo) const { return GetNext(kAddrFilter, aIterator, aInfo); }
|
||||
|
||||
/**
|
||||
* Adds a fixed received signal strength entry for the messages from a given Extended Address.
|
||||
*
|
||||
* @param[in] aExtAddress An Extended Address
|
||||
* @param[in] aExtAddress An Extended Address.
|
||||
* @param[in] aRss The received signal strength to set.
|
||||
*
|
||||
* @retval kErrorNone Successfully set @p aRss for @p aExtAddress.
|
||||
* @retval kErrorNoBufs No available entry exists.
|
||||
* @retval kErrorNone Successfully set @p aRss for @p aExtAddress.
|
||||
* @retval kErrorInvalidArgs @p aRss is not valid (equal to `kFixedRssDisabled`).
|
||||
* @retval kErrorNoBufs No available entry exists.
|
||||
*/
|
||||
Error AddRssIn(const ExtAddress &aExtAddress, int8_t aRss);
|
||||
|
||||
@@ -158,9 +163,9 @@ public:
|
||||
*
|
||||
* No action is performed if there is no existing entry in the filter list matching the given Extended Address.
|
||||
*
|
||||
* @param[in] aExtAddress A Extended Address.
|
||||
* @param[in] aExtAddress An Extended Address.
|
||||
*/
|
||||
void RemoveRssIn(const ExtAddress &aExtAddress);
|
||||
void RemoveRssIn(const ExtAddress &aExtAddress) { RemoveEntry(kRssFilter, aExtAddress); }
|
||||
|
||||
/**
|
||||
* Sets the default received signal strength.
|
||||
@@ -180,21 +185,21 @@ public:
|
||||
/**
|
||||
* Clears all the received signal strength settings (including the default RSS-In).
|
||||
*/
|
||||
void ClearAllRssIn(void);
|
||||
void ClearAllRssIn(void) { ClearAll(kRssFilter); }
|
||||
|
||||
/**
|
||||
* Iterates through RssIn filter entry.
|
||||
*
|
||||
* @param[in,out] aIterator A reference to the MAC filter iterator context. To get the first in-use RssIn
|
||||
* filter entry, it should be set to OT_MAC_FILTER_ITERATOR_INIT.
|
||||
* @param[out] aEntry A reference to where the information is placed. The last entry would have the
|
||||
* filter entry, it should be set to `kIteratorInit`.
|
||||
* @param[out] aInfo A reference to where the entry information is placed. The last entry would have the
|
||||
* Extended Address as all 0xff to indicate the default received signal strength
|
||||
* if it was set.
|
||||
*
|
||||
* @retval kErrorNone Successfully retrieved the next RssIn filter entry.
|
||||
* @retval kErrorNotFound No subsequent entry exists.
|
||||
*/
|
||||
Error GetNextRssIn(Iterator &aIterator, Entry &aEntry) const;
|
||||
Error GetNextRssIn(Iterator &aIterator, EntryInfo &aInfo) const { return GetNext(kRssFilter, aIterator, aInfo); }
|
||||
|
||||
/**
|
||||
* Applies the filter rules on a given Extended Address.
|
||||
@@ -224,24 +229,47 @@ public:
|
||||
Error ApplyToRxFrame(RxFrame &aRxFrame, const ExtAddress &aExtAddress, Neighbor *aNeighbor = nullptr) const;
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_MAC_FILTER_SIZE;
|
||||
static constexpr uint8_t kMaxEntries = OPENTHREAD_CONFIG_MAC_FILTER_SIZE;
|
||||
|
||||
struct FilterEntry
|
||||
enum Type : bool
|
||||
{
|
||||
bool mFiltered; // Indicates whether or not this entry is filtered (allowlist/denylist modes).
|
||||
int8_t mRssIn; // The RssIn value for this entry or `kFixedRssDisabled`.
|
||||
ExtAddress mExtAddress; // IEEE 802.15.4 Extended Address.
|
||||
|
||||
bool IsInUse(void) const { return mFiltered || (mRssIn != kFixedRssDisabled); }
|
||||
kRssFilter,
|
||||
kAddrFilter,
|
||||
};
|
||||
|
||||
FilterEntry *FindAvailableEntry(void);
|
||||
const FilterEntry *FindEntry(const ExtAddress &aExtAddress) const;
|
||||
FilterEntry *FindEntry(const ExtAddress &aExtAddress) { return AsNonConst(AsConst(this)->FindEntry(aExtAddress)); }
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
enum NotInUseMatcher : uint8_t
|
||||
{
|
||||
kNotInUse,
|
||||
};
|
||||
|
||||
Mode mMode;
|
||||
int8_t mDefaultRssIn;
|
||||
FilterEntry mFilterEntries[kMaxEntries];
|
||||
void Init(const ExtAddress &aExtAddress);
|
||||
const ExtAddress &GetExtAddress(void) const { return mExtAddress; }
|
||||
bool IsInAddrFilter(void) const { return mInAddrFilter; }
|
||||
void SetInAddrFilter(bool aInAddrFilter) { mInAddrFilter = aInAddrFilter; }
|
||||
bool IsInRssFilter(void) const { return (mRssIn != kFixedRssDisabled); }
|
||||
int8_t GetRssIn(void) const { return mRssIn; }
|
||||
void SetRssIn(int8_t aRss) { mRssIn = aRss; }
|
||||
void ClearRssIn(void) { mRssIn = kFixedRssDisabled; }
|
||||
bool Matches(const ExtAddress &aExtAddress) const { return mExtAddress == aExtAddress; }
|
||||
bool Matches(NotInUseMatcher) const { return !IsInAddrFilter() && !IsInRssFilter(); }
|
||||
|
||||
private:
|
||||
ExtAddress mExtAddress;
|
||||
bool mInAddrFilter;
|
||||
int8_t mRssIn;
|
||||
};
|
||||
|
||||
Error AddOrUpdateEntry(Type aType, const ExtAddress &aExtAddress, int8_t aRss);
|
||||
void RemoveEntry(Type aType, const ExtAddress &aExtAddress);
|
||||
Error GetNext(Type aType, Iterator &aIterator, EntryInfo &aInfo) const;
|
||||
void ClearAll(Type aType);
|
||||
|
||||
Array<Entry, kMaxEntries> mEntries;
|
||||
Mode mMode;
|
||||
int8_t mDefaultRssIn;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -234,6 +234,7 @@ ot_unit_test(link_quality)
|
||||
ot_unit_test(linked_list)
|
||||
ot_unit_test(lowpan)
|
||||
ot_unit_test(ltv)
|
||||
ot_unit_test(mac_filter)
|
||||
ot_unit_test(mac_frame)
|
||||
ot_unit_test(macros)
|
||||
ot_unit_test(mdns)
|
||||
|
||||
@@ -0,0 +1,667 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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.
|
||||
*/
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.h"
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/clearable.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "mac/mac_filter.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
|
||||
static Mac::ExtAddress MakeExtAddress(uint16_t aIndex)
|
||||
{
|
||||
Mac::ExtAddress addr;
|
||||
|
||||
ClearAllBytes(addr);
|
||||
BigEndian::WriteUint16(aIndex, &addr.m8[sizeof(Mac::ExtAddress) - sizeof(uint16_t)]);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void TestFilterMode(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::ExtAddress addr = MakeExtAddress(1);
|
||||
int8_t rss;
|
||||
|
||||
printf("TestFilterMode\n");
|
||||
|
||||
// Verify initial mode and transitions between modes.
|
||||
|
||||
VerifyOrQuit(filter.GetMode() == Mac::Filter::kModeRssInOnly);
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeAllowlist);
|
||||
VerifyOrQuit(filter.GetMode() == Mac::Filter::kModeAllowlist);
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeDenylist);
|
||||
VerifyOrQuit(filter.GetMode() == Mac::Filter::kModeDenylist);
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeRssInOnly);
|
||||
VerifyOrQuit(filter.GetMode() == Mac::Filter::kModeRssInOnly);
|
||||
|
||||
// Verify Apply() behavior when filter list is empty.
|
||||
|
||||
SuccessOrQuit(filter.Apply(addr, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeAllowlist);
|
||||
VerifyOrQuit(filter.Apply(addr, rss) == kErrorAddressFiltered);
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeDenylist);
|
||||
SuccessOrQuit(filter.Apply(addr, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
}
|
||||
|
||||
static void TestAddressAllowlist(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
Mac::ExtAddress addr3 = MakeExtAddress(3);
|
||||
int8_t rss;
|
||||
|
||||
printf("TestAddressAllowlist\n");
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeAllowlist);
|
||||
|
||||
// Add addresses and verify allowlist filtering.
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.AddAddress(addr2));
|
||||
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
VerifyOrQuit(filter.Apply(addr3, rss) == kErrorAddressFiltered);
|
||||
|
||||
// Adding duplicate address should succeed and keep entry in allowlist.
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
|
||||
// Remove an address and verify it is filtered.
|
||||
|
||||
filter.RemoveAddress(addr1);
|
||||
VerifyOrQuit(filter.Apply(addr1, rss) == kErrorAddressFiltered);
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
|
||||
// Removing non-existent address should not affect existing entries.
|
||||
|
||||
filter.RemoveAddress(addr3);
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
|
||||
// Clear all addresses and verify all are filtered.
|
||||
|
||||
filter.ClearAddresses();
|
||||
VerifyOrQuit(filter.Apply(addr2, rss) == kErrorAddressFiltered);
|
||||
}
|
||||
|
||||
static void TestAddressDenylist(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
Mac::ExtAddress addr3 = MakeExtAddress(3);
|
||||
int8_t rss;
|
||||
|
||||
printf("TestAddressDenylist\n");
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeDenylist);
|
||||
|
||||
// Add addresses and verify denylist filtering.
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.AddAddress(addr2));
|
||||
|
||||
VerifyOrQuit(filter.Apply(addr1, rss) == kErrorAddressFiltered);
|
||||
VerifyOrQuit(filter.Apply(addr2, rss) == kErrorAddressFiltered);
|
||||
SuccessOrQuit(filter.Apply(addr3, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
|
||||
// Remove an address from denylist and verify it is allowed.
|
||||
|
||||
filter.RemoveAddress(addr1);
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(filter.Apply(addr2, rss) == kErrorAddressFiltered);
|
||||
|
||||
// Removing non-existent address should not affect existing entries.
|
||||
|
||||
filter.RemoveAddress(addr3);
|
||||
VerifyOrQuit(filter.Apply(addr2, rss) == kErrorAddressFiltered);
|
||||
|
||||
// Clear all addresses and verify all are allowed.
|
||||
|
||||
filter.ClearAddresses();
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
}
|
||||
|
||||
static void TestAddressIteration(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::Filter::Iterator iter;
|
||||
Mac::Filter::EntryInfo info;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
Mac::ExtAddress addr3 = MakeExtAddress(3);
|
||||
uint16_t count;
|
||||
bool foundAddr1;
|
||||
bool foundAddr2;
|
||||
bool foundAddr3;
|
||||
|
||||
printf("TestAddressIteration\n");
|
||||
|
||||
// Empty filter should return kErrorNotFound.
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
|
||||
// Add multiple addresses and iterate through all entries.
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.AddAddress(addr2));
|
||||
SuccessOrQuit(filter.AddAddress(addr3));
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
count = 0;
|
||||
foundAddr1 = false;
|
||||
foundAddr2 = false;
|
||||
foundAddr3 = false;
|
||||
|
||||
while (filter.GetNextAddress(iter, info) == kErrorNone)
|
||||
{
|
||||
count++;
|
||||
VerifyOrQuit(info.mRssIn == Mac::Filter::kFixedRssDisabled);
|
||||
if (AsCoreType(&info.mExtAddress) == addr1)
|
||||
{
|
||||
foundAddr1 = true;
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == addr2)
|
||||
{
|
||||
foundAddr2 = true;
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == addr3)
|
||||
{
|
||||
foundAddr3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(count == 3);
|
||||
VerifyOrQuit(foundAddr1 && foundAddr2 && foundAddr3);
|
||||
|
||||
// Remove middle entry and verify remaining entries iterate correctly.
|
||||
|
||||
filter.RemoveAddress(addr2);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
count = 0;
|
||||
foundAddr1 = false;
|
||||
foundAddr2 = false;
|
||||
foundAddr3 = false;
|
||||
|
||||
while (filter.GetNextAddress(iter, info) == kErrorNone)
|
||||
{
|
||||
count++;
|
||||
if (AsCoreType(&info.mExtAddress) == addr1)
|
||||
{
|
||||
foundAddr1 = true;
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == addr2)
|
||||
{
|
||||
foundAddr2 = true;
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == addr3)
|
||||
{
|
||||
foundAddr3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(count == 2);
|
||||
VerifyOrQuit(foundAddr1 && !foundAddr2 && foundAddr3);
|
||||
|
||||
// Clear all addresses and verify iteration returns kErrorNotFound.
|
||||
|
||||
filter.ClearAddresses();
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
}
|
||||
|
||||
static void TestRssInFiltering(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
int8_t rss;
|
||||
|
||||
printf("TestRssInFiltering\n");
|
||||
|
||||
// Verify kFixedRssDisabled cannot be added as valid RSS.
|
||||
|
||||
VerifyOrQuit(filter.AddRssIn(addr1, Mac::Filter::kFixedRssDisabled) == kErrorInvalidArgs);
|
||||
|
||||
// Add fixed RSS and verify retrieval.
|
||||
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -70));
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == -70);
|
||||
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
|
||||
// Update fixed RSS for existing entry.
|
||||
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -50));
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == -50);
|
||||
|
||||
// Remove fixed RSS and verify default is restored.
|
||||
|
||||
filter.RemoveRssIn(addr1);
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
|
||||
// Removing non-existent RSS entry should not cause issues.
|
||||
|
||||
filter.RemoveRssIn(addr2);
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
}
|
||||
|
||||
static void TestDefaultRssIn(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
int8_t rss;
|
||||
|
||||
printf("TestDefaultRssIn\n");
|
||||
|
||||
// Set default RSS and verify it applies to all addresses.
|
||||
|
||||
filter.SetDefaultRssIn(-65);
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == -65);
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
VerifyOrQuit(rss == -65);
|
||||
|
||||
// Explicit RSS should override default RSS.
|
||||
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -40));
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == -40);
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
VerifyOrQuit(rss == -65);
|
||||
|
||||
// Removing explicit RSS falls back to default RSS.
|
||||
|
||||
filter.RemoveRssIn(addr1);
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == -65);
|
||||
|
||||
// Clear default RSS and verify no fixed RSS is applied.
|
||||
|
||||
filter.ClearDefaultRssIn();
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
|
||||
// ClearAllRssIn() clears both explicit and default RSS.
|
||||
|
||||
filter.SetDefaultRssIn(-80);
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -30));
|
||||
SuccessOrQuit(filter.AddRssIn(addr2, -45));
|
||||
filter.ClearAllRssIn();
|
||||
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
SuccessOrQuit(filter.Apply(addr2, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
}
|
||||
|
||||
static void TestRssInIteration(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::Filter::Iterator iter;
|
||||
Mac::Filter::EntryInfo info;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
Mac::ExtAddress defaultRssAddr;
|
||||
uint16_t count;
|
||||
bool foundAddr1;
|
||||
bool foundAddr2;
|
||||
bool foundDefault;
|
||||
|
||||
printf("TestRssInIteration\n");
|
||||
|
||||
defaultRssAddr.Fill(0xff);
|
||||
|
||||
// Empty filter with no default RSS yields nothing.
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
// Empty filter with default RSS yields synthetic all-0xff entry.
|
||||
|
||||
filter.SetDefaultRssIn(-75);
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextRssIn(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == defaultRssAddr);
|
||||
VerifyOrQuit(info.mRssIn == -75);
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
// Explicit entries are yielded along with default RSS.
|
||||
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -60));
|
||||
SuccessOrQuit(filter.AddRssIn(addr2, -80));
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
count = 0;
|
||||
foundAddr1 = false;
|
||||
foundAddr2 = false;
|
||||
foundDefault = false;
|
||||
|
||||
while (filter.GetNextRssIn(iter, info) == kErrorNone)
|
||||
{
|
||||
count++;
|
||||
if (AsCoreType(&info.mExtAddress) == addr1)
|
||||
{
|
||||
foundAddr1 = true;
|
||||
VerifyOrQuit(info.mRssIn == -60);
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == addr2)
|
||||
{
|
||||
foundAddr2 = true;
|
||||
VerifyOrQuit(info.mRssIn == -80);
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == defaultRssAddr)
|
||||
{
|
||||
foundDefault = true;
|
||||
VerifyOrQuit(info.mRssIn == -75);
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(count == 3);
|
||||
VerifyOrQuit(foundAddr1 && foundAddr2 && foundDefault);
|
||||
|
||||
// Clear default RSS and verify only explicit entries are yielded.
|
||||
|
||||
filter.ClearDefaultRssIn();
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
count = 0;
|
||||
foundAddr1 = false;
|
||||
foundAddr2 = false;
|
||||
foundDefault = false;
|
||||
|
||||
while (filter.GetNextRssIn(iter, info) == kErrorNone)
|
||||
{
|
||||
count++;
|
||||
if (AsCoreType(&info.mExtAddress) == addr1)
|
||||
{
|
||||
foundAddr1 = true;
|
||||
VerifyOrQuit(info.mRssIn == -60);
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == addr2)
|
||||
{
|
||||
foundAddr2 = true;
|
||||
VerifyOrQuit(info.mRssIn == -80);
|
||||
}
|
||||
else if (AsCoreType(&info.mExtAddress) == defaultRssAddr)
|
||||
{
|
||||
foundDefault = true;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(count == 2);
|
||||
VerifyOrQuit(foundAddr1 && foundAddr2 && !foundDefault);
|
||||
}
|
||||
|
||||
static void TestAddressAndRssCoexistence(void)
|
||||
{
|
||||
Mac::Filter filter;
|
||||
Mac::Filter::Iterator iter;
|
||||
Mac::Filter::EntryInfo info;
|
||||
Mac::ExtAddress addr1 = MakeExtAddress(1);
|
||||
Mac::ExtAddress addr2 = MakeExtAddress(2);
|
||||
int8_t rss;
|
||||
|
||||
printf("TestAddressAndRssCoexistence\n");
|
||||
|
||||
filter.SetMode(Mac::Filter::kModeAllowlist);
|
||||
|
||||
// Add both address and RSS-In to the same entry.
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -55));
|
||||
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == -55);
|
||||
|
||||
// Verify entry is present in both address and RSS iterations.
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextAddress(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == addr1);
|
||||
VerifyOrQuit(info.mRssIn == -55);
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextRssIn(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == addr1);
|
||||
VerifyOrQuit(info.mRssIn == -55);
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
// Remove address filter only; RSS-In entry must persist.
|
||||
|
||||
filter.RemoveAddress(addr1);
|
||||
VerifyOrQuit(filter.Apply(addr1, rss) == kErrorAddressFiltered);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextRssIn(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == addr1);
|
||||
VerifyOrQuit(info.mRssIn == -55);
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
// Re-add address and remove RSS-In; address filter must persist.
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
filter.RemoveRssIn(addr1);
|
||||
|
||||
SuccessOrQuit(filter.Apply(addr1, rss));
|
||||
VerifyOrQuit(rss == Mac::Filter::kFixedRssDisabled);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextAddress(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == addr1);
|
||||
VerifyOrQuit(info.mRssIn == Mac::Filter::kFixedRssDisabled);
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
// Remove address; entry should be completely removed.
|
||||
|
||||
filter.RemoveAddress(addr1);
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
|
||||
// ClearAddresses() removes address filters while preserving RSS-In entries.
|
||||
|
||||
filter.ClearAllRssIn();
|
||||
filter.ClearAddresses();
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -48));
|
||||
SuccessOrQuit(filter.AddAddress(addr2));
|
||||
|
||||
filter.ClearAddresses();
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextRssIn(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == addr1);
|
||||
VerifyOrQuit(info.mRssIn == -48);
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
// ClearAllRssIn() removes RSS-In entries while preserving address filters.
|
||||
|
||||
filter.ClearAllRssIn();
|
||||
filter.ClearAddresses();
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(addr1));
|
||||
SuccessOrQuit(filter.AddRssIn(addr1, -48));
|
||||
SuccessOrQuit(filter.AddRssIn(addr2, -62));
|
||||
|
||||
filter.ClearAllRssIn();
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
VerifyOrQuit(filter.GetNextRssIn(iter, info) == kErrorNotFound);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
SuccessOrQuit(filter.GetNextAddress(iter, info));
|
||||
VerifyOrQuit(AsCoreType(&info.mExtAddress) == addr1);
|
||||
VerifyOrQuit(info.mRssIn == Mac::Filter::kFixedRssDisabled);
|
||||
VerifyOrQuit(filter.GetNextAddress(iter, info) == kErrorNotFound);
|
||||
}
|
||||
|
||||
static void TestCapacityLimits(void)
|
||||
{
|
||||
constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_MAC_FILTER_SIZE;
|
||||
|
||||
Mac::Filter filter;
|
||||
Mac::Filter::Iterator iter;
|
||||
Mac::Filter::EntryInfo info;
|
||||
Mac::ExtAddress extraAddr = MakeExtAddress(kMaxEntries + 1);
|
||||
uint16_t count;
|
||||
uint16_t i;
|
||||
|
||||
printf("TestCapacityLimits\n");
|
||||
|
||||
// Fill filter to maximum capacity.
|
||||
|
||||
for (i = 1; i <= kMaxEntries; i++)
|
||||
{
|
||||
SuccessOrQuit(filter.AddAddress(MakeExtAddress(i)));
|
||||
}
|
||||
|
||||
// Adding beyond capacity fails with kErrorNoBufs.
|
||||
|
||||
VerifyOrQuit(filter.AddAddress(extraAddr) == kErrorNoBufs);
|
||||
|
||||
// Adding RSS-In to an existing address entry reuses slot.
|
||||
|
||||
SuccessOrQuit(filter.AddRssIn(MakeExtAddress(1), -60));
|
||||
|
||||
// Adding RSS-In for a new address fails when table is full.
|
||||
|
||||
VerifyOrQuit(filter.AddRssIn(extraAddr, -60) == kErrorNoBufs);
|
||||
|
||||
// Free slot by removing an address-only entry.
|
||||
|
||||
filter.RemoveAddress(MakeExtAddress(2));
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(extraAddr));
|
||||
|
||||
VerifyOrQuit(filter.AddAddress(MakeExtAddress(kMaxEntries + 2)) == kErrorNoBufs);
|
||||
|
||||
// Removing address from entry with active RSS-In does not free slot.
|
||||
|
||||
filter.RemoveAddress(MakeExtAddress(1));
|
||||
|
||||
VerifyOrQuit(filter.AddAddress(MakeExtAddress(kMaxEntries + 2)) == kErrorNoBufs);
|
||||
|
||||
// Removing RSS-In now frees the slot.
|
||||
|
||||
filter.RemoveRssIn(MakeExtAddress(1));
|
||||
|
||||
SuccessOrQuit(filter.AddAddress(MakeExtAddress(kMaxEntries + 2)));
|
||||
|
||||
// Clear all entries and verify all slots are freed.
|
||||
|
||||
filter.ClearAddresses();
|
||||
filter.ClearAllRssIn();
|
||||
|
||||
count = 0;
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
while (filter.GetNextAddress(iter, info) == kErrorNone)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
VerifyOrQuit(count == 0);
|
||||
|
||||
iter = Mac::Filter::kIteratorInit;
|
||||
while (filter.GetNextRssIn(iter, info) == kErrorNone)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
VerifyOrQuit(count == 0);
|
||||
|
||||
// Verify all slots can be populated again up to capacity.
|
||||
|
||||
for (i = 1; i <= kMaxEntries; i++)
|
||||
{
|
||||
SuccessOrQuit(filter.AddAddress(MakeExtAddress(i)));
|
||||
}
|
||||
VerifyOrQuit(filter.AddAddress(extraAddr) == kErrorNoBufs);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
ot::TestFilterMode();
|
||||
ot::TestAddressAllowlist();
|
||||
ot::TestAddressDenylist();
|
||||
ot::TestAddressIteration();
|
||||
ot::TestRssInFiltering();
|
||||
ot::TestDefaultRssIn();
|
||||
ot::TestRssInIteration();
|
||||
ot::TestAddressAndRssCoexistence();
|
||||
ot::TestCapacityLimits();
|
||||
printf("All tests passed\n");
|
||||
#else
|
||||
printf("MAC filter is not enabled\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user