/* * Copyright (c) 2023, 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 CLI for MAC Filter. */ #include "cli_mac_filter.hpp" #include "cli/cli.hpp" #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE namespace ot { namespace Cli { void MacFilter::OutputFilter(uint8_t aFilters) { otMacFilterEntry entry; otMacFilterIterator iterator; if (aFilters & kAddressFilter) { if ((aFilters & ~kAddressFilter) != 0) { OutputFormat("Address Mode: "); } OutputLine("%s", AddressModeToString(otLinkFilterGetAddressMode(GetInstancePtr()))); iterator = OT_MAC_FILTER_ITERATOR_INIT; while (otLinkFilterGetNextAddress(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE) { OutputEntry(entry); } } if (aFilters & kRssFilter) { if ((aFilters & ~kRssFilter) != 0) { OutputLine("RssIn List:"); } iterator = OT_MAC_FILTER_ITERATOR_INIT; while (otLinkFilterGetNextRssIn(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE) { if (IsDefaultRss(entry.mExtAddress)) { OutputLine("Default rss: %d (lqi %u)", entry.mRssIn, otLinkConvertRssToLinkQuality(GetInstancePtr(), entry.mRssIn)); } else { OutputEntry(entry); } } } } bool MacFilter::IsDefaultRss(const otExtAddress &aExtAddress) { // In default RSS entry, the extended address will be all `0xff`. bool isDefault = true; for (uint8_t byte : aExtAddress.m8) { if (byte != 0xff) { isDefault = false; break; } } return isDefault; } const char *MacFilter::AddressModeToString(otMacFilterAddressMode aMode) { static const char *const kModeStrings[] = { "Disabled", // (0) OT_MAC_FILTER_ADDRESS_MODE_DISABLED "Allowlist", // (1) OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST "Denylist", // (2) OT_MAC_FILTER_ADDRESS_MODE_DENYLIST }; static_assert(0 == OT_MAC_FILTER_ADDRESS_MODE_DISABLED, "OT_MAC_FILTER_ADDRESS_MODE_DISABLED value is incorrect"); static_assert(1 == OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST, "OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST value is incorrect"); static_assert(2 == OT_MAC_FILTER_ADDRESS_MODE_DENYLIST, "OT_MAC_FILTER_ADDRESS_MODE_DENYLIST value is incorrect"); return Stringify(aMode, kModeStrings); } void MacFilter::OutputEntry(const otMacFilterEntry &aEntry) { OutputExtAddress(aEntry.mExtAddress); if (aEntry.mRssIn != OT_MAC_FILTER_FIXED_RSS_DISABLED) { OutputFormat(" : rss %d (lqi %d)", aEntry.mRssIn, otLinkConvertRssToLinkQuality(GetInstancePtr(), aEntry.mRssIn)); } OutputNewLine(); } template <> otError MacFilter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; otExtAddress extAddr; /** * @cli macfilter addr * @code * macfilter addr * Allowlist * 0f6127e33af6b403 : rss -95 (lqi 1) * 0f6127e33af6b402 * Done * @endcode * @par * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * @par * Provides the following information: * - Current mode of the MAC filter list: Either `AllowList`, `DenyList,` or `Disabled` * - A list of all the extended addresses in the filter. The received signal strength (rss) and * link quality indicator (lqi) are listed next to the address if these values have been set to be * different from the default values. * @sa otLinkFilterGetAddressMode */ if (aArgs[0].IsEmpty()) { OutputFilter(kAddressFilter); } /** * @cli macfilter addr add * @code * macfilter addr add 0f6127e33af6b403 -95 * Done * @endcode * @code * macfilter addr add 0f6127e33af6b402 * Done * @endcode * @cparam macfilter addr add @ca{extaddr} [@ca{rss}] * @par * Is available only when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * @par * Adds an IEEE 802.15.4 Extended Address to the MAC filter list. * If you specify the optional `rss` argument, this fixes the received signal strength for messages from the * address. If you do not use the `rss` option, the address will use whatever default value you have set. * If you have not set a default, the signal strength will be the over-air signal. * @sa otLinkFilterAddAddress */ else if (aArgs[0] == "add") { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); error = otLinkFilterAddAddress(GetInstancePtr(), &extAddr); VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY); if (!aArgs[2].IsEmpty()) { int8_t rss; SuccessOrExit(error = aArgs[2].ParseAsInt8(rss)); SuccessOrExit(error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss)); } } /** * @cli macfilter addr remove * @code * macfilter addr remove 0f6127e33af6b402 * Done * @endcode * @cparam macfilter addr remove @ca{extaddr} * @par * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * @par * This command removes the specified extended address from the MAC filter list. * @note No action is performed if the specified extended address does not match an entry in the MAC filter list. * @sa otLinkFilterRemoveAddress */ else if (aArgs[0] == "remove") { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); otLinkFilterRemoveAddress(GetInstancePtr(), &extAddr); } /** * @cli macfilter addr clear * @code * macfilter addr clear * Done * @endcode * @par * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * @par * This command clears all the extended addresses from the MAC filter list. * @note This command does not affect entries in the `RssIn` list. That list contains extended addresses where the * `rss` has been set to a fixed value that differs from the default. * @sa otLinkFilterClearAddresses */ else if (aArgs[0] == "clear") { otLinkFilterClearAddresses(GetInstancePtr()); } else { static const char *const kModeCommands[] = { /** * @cli macfilter addr disable * @code * macfilter addr disable * Done * @endcode * @par * Disables MAC filter modes. */ "disable", // (0) OT_MAC_FILTER_ADDRESS_MODE_DISABLED /** * @cli macfilter addr allowlist * @code * macfilter addr allowlist * Done * @endcode * @par * Enables the `allowlist` MAC filter mode, which means that only the MAC addresses in the MAC filter list * will be allowed access. * @sa otLinkFilterSetAddressMode */ "allowlist", // (1) OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST /** * @cli macfilter addr denylist * @code * macfilter addr denylist * Done * @endcode * @par * Enables the `denylist` MAC filter mode, which means that all MAC addresses in the MAC filter list * will be denied access. * @sa otLinkFilterSetAddressMode */ "denylist", // (2) OT_MAC_FILTER_ADDRESS_MODE_DENYLIST }; for (size_t index = 0; index < OT_ARRAY_LENGTH(kModeCommands); index++) { if (aArgs[0] == kModeCommands[index]) { VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); otLinkFilterSetAddressMode(GetInstancePtr(), static_cast(index)); ExitNow(); } } error = OT_ERROR_INVALID_COMMAND; } exit: return error; } /** * @cli macfilter rss * @code * macfilter rss * 0f6127e33af6b403 : rss -95 (lqi 1) * Default rss: -50 (lqi 3) * Done * @endcode * @par * Provides the following information: * - Listing of all the extended addresses * where the received signal strength (`rss`) has been set to be different from * the default value. The link quality indicator (`lqi`) is also shown. The `rss` * and `lqi` settings map to each other. If you set one, the value of the other * gets set automatically. This list of addresses is called the `RssIn List`. * Setting either the `rsi` or the `lqi` adds the corresponding extended address * to the `RssIn` list. * - `Default rss`: Shows the default values, if applicable, for the `rss` and `lqi` settings. * @sa otLinkFilterGetNextRssIn */ template <> otError MacFilter::Process(Arg aArgs[]) { otError error = OT_ERROR_NONE; otExtAddress extAddr; int8_t rss; if (aArgs[0].IsEmpty()) { OutputFilter(kRssFilter); } /** * @cli macfilter rss add-lqi * @code * macfilter rss add-lqi * 3 * Done * @endcode * @code * macfilter rss add-lqi 0f6127e33af6b404 2 * Done * @endcode * @cparam macfilter rss add-lqi @ca{extaddr} @ca{lqi} * To set a default value for the link quality indicator for all received messages, * use the `*` for the `extaddr` argument. The allowed range is 0 to 3. * @par * Adds the specified Extended Address to the `RssIn` list (or modifies an existing address in the `RssIn` list) * and sets the fixed link quality indicator for messages from that address. * The Extended Address * does not necessarily have to be in the `address allowlist/denylist` filter to set the `lqi`. * @note The `RssIn` list contains Extended Addresses whose `lqi` or * received signal strength (`rss`) values have been set to be different from the defaults. * The `lqi` will automatically get converted to a corresponding `rss` value. * @par * This is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled. * @sa otLinkConvertLinkQualityToRss * @sa otLinkFilterSetDefaultRssIn */ else if (aArgs[0] == "add-lqi") { uint8_t linkQuality; SuccessOrExit(error = aArgs[2].ParseAsUint8(linkQuality)); VerifyOrExit(linkQuality <= 3, error = OT_ERROR_INVALID_ARGS); rss = otLinkConvertLinkQualityToRss(GetInstancePtr(), linkQuality); if (aArgs[1] == "*") { otLinkFilterSetDefaultRssIn(GetInstancePtr(), rss); } else { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss); } } /** * @cli macfilter rss add * @code * macfilter rss add * -50 * Done * @endcode * @code * macfilter rss add 0f6127e33af6b404 -85 * Done * @endcode * @cparam macfilter rss add @ca{extaddr} @ca{rss} * To set a default value for the received signal strength for all received messages, * use the `*` for the `extaddr` argument. * @par api_copy * #otLinkFilterAddRssIn */ else if (aArgs[0] == "add") { SuccessOrExit(error = aArgs[2].ParseAsInt8(rss)); if (aArgs[1] == "*") { otLinkFilterSetDefaultRssIn(GetInstancePtr(), rss); } else { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss); } } /** * @cli macfilter rss remove * @code * macfilter rss remove * * Done * @endcode * @code * macfilter rss remove 0f6127e33af6b404 * Done * @endcode * @cparam macfilter rss remove @ca{extaddr} * If you wish to remove the default received signal strength and link quality indicator settings, * use the `*` as the `extaddr`. This unsets the defaults but does not remove * entries from the `RssIn` list. * @par api_copy * #otLinkFilterRemoveRssIn */ else if (aArgs[0] == "remove") { if (aArgs[1] == "*") { otLinkFilterClearDefaultRssIn(GetInstancePtr()); } else { SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8)); otLinkFilterRemoveRssIn(GetInstancePtr(), &extAddr); } } /** * @cli macfilter rss clear * @code * macfilter rss clear * Done * @endcode * @par api_copy * #otLinkFilterClearAllRssIn */ else if (aArgs[0] == "clear") { otLinkFilterClearAllRssIn(GetInstancePtr()); } else { error = OT_ERROR_INVALID_COMMAND; } exit: return error; } otError MacFilter::Process(Arg aArgs[]) { #define CmdEntry(aCommandString) \ { \ aCommandString, &MacFilter::Process \ } static constexpr Command kCommands[] = { CmdEntry("addr"), CmdEntry("rss"), }; #undef CmdEntry static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); otError error = OT_ERROR_INVALID_COMMAND; const Command *command; /** * @cli macfilter * @code * macfilter * Address Mode: Allowlist * 0f6127e33af6b403 : rss -95 (lqi 1) * 0f6127e33af6b402 * RssIn List: * 0f6127e33af6b403 : rss -95 (lqi 1) * Default rss: -50 (lqi 3) * Done * @endcode * @par * Provides the following information: * - `Address Mode`: Current mode of the MAC filter: Either `AllowList`, `DenyList,` or `Disabled` * - A list of all the extended addresses in the MAC filter list. The received signal strength (rss) and * link quality indicator (lqi) are listed next to the address if these values have been set to be * different from the default values. * - A separate list (`RssIn List`) that shows all the extended addresses where the `rss` has been set to * be different from the default value. * - `Default rss`: Shows the default values, if applicable, for the `rss` and `lqi` settings. * @note An extended address can be in the `RssIn` list without being in the MAC filter list. * @sa otLinkFilterSetAddressMode * @sa otLinkFilterGetNextAddress * @sa otLinkFilterGetNextRssIn */ if (aArgs[0].IsEmpty()) { OutputFilter(kAddressFilter | kRssFilter); ExitNow(error = OT_ERROR_NONE); } command = BinarySearch::Find(aArgs[0].GetCString(), kCommands); VerifyOrExit(command != nullptr); error = (this->*command->mHandler)(aArgs + 1); exit: return error; } } // namespace Cli } // namespace ot #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE