diff --git a/src/platform/silabs/ConnectivityManagerImpl.h b/src/platform/silabs/ConnectivityManagerImpl.h index 54a6b97c5e5fa1..ab62d4d350a859 100644 --- a/src/platform/silabs/ConnectivityManagerImpl.h +++ b/src/platform/silabs/ConnectivityManagerImpl.h @@ -36,6 +36,7 @@ #include #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION +#include "EndpointQueueFilter.h" #include #else #include @@ -131,6 +132,9 @@ class ConnectivityManagerImpl final : public ConnectivityManager, static void DriveStationState(::chip::System::Layer * aLayer, void * aAppState); void UpdateInternetConnectivityState(void); +#if CHIP_CONFIG_ENABLE_ICD_SERVER + Inet::SilabsEndpointQueueFilter::EndpointQueueFilter mEndpointQueueFilter; +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER #endif }; diff --git a/src/platform/silabs/ConnectivityManagerImpl_WIFI.cpp b/src/platform/silabs/ConnectivityManagerImpl_WIFI.cpp index 0d9d63317ef637..3887e2eb64202d 100644 --- a/src/platform/silabs/ConnectivityManagerImpl_WIFI.cpp +++ b/src/platform/silabs/ConnectivityManagerImpl_WIFI.cpp @@ -40,6 +40,7 @@ #endif #include "CHIPDevicePlatformConfig.h" +#include "EndpointQueueFilter.h" #include using namespace ::chip; @@ -426,6 +427,32 @@ void ConnectivityManagerImpl::UpdateInternetConnectivityState(void) event.InternetConnectivityChange.IPv6 = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn); event.InternetConnectivityChange.ipAddress = addr; +#if CHIP_CONFIG_ENABLE_ICD_SERVER + { + sl_wfx_mac_address_t macaddr; + wfx_get_wifi_mac_addr(SL_WFX_STA_INTERFACE, &macaddr); + char macaddrString[13]; // 12 characters + null terminator + sprintf(macaddrString, "%02X%02X%02X%02X%02X%02X", macaddr.octet[0], macaddr.octet[1], macaddr.octet[2], + macaddr.octet[3], macaddr.octet[4], macaddr.octet[5]); + EndpointQueueFilterConfig config; + config.allowedQueuedPackets = 20; // Set the desired value + + mEndpointQueueFilter.SetConfig(config); + + // Convert macaddrString to Span + Span macaddrSpan(reinterpret_cast(macaddrString), sizeof(macaddrString)); + + if (mEndpointQueueFilter.SetHostName(macaddrSpan) == CHIP_NO_ERROR) + { + UDPEndPointImpl::SetQueueFilter(&mEndpointQueueFilter); + } + else + { + ChipLogError(DeviceLayer, "Failed to set host name filter"); + } + } +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER + if (haveIPv4Conn != hadIPv4Conn) { ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv4", (haveIPv4Conn) ? "ESTABLISHED" : "LOST"); diff --git a/src/platform/silabs/EndpointQueueFilter.cpp b/src/platform/silabs/EndpointQueueFilter.cpp new file mode 100644 index 00000000000000..9a46f858cecc7e --- /dev/null +++ b/src/platform/silabs/EndpointQueueFilter.cpp @@ -0,0 +1,121 @@ +#include "EndpointQueueFilter.h" +#include +#include +#include +#include +#include +#include + +using namespace ::chip; + +namespace chip { +namespace Inet { + +using FilterOutcome = EndpointQueueFilter::FilterOutcome; + +namespace { + +bool IsValidMdnsHostName(const Span & hostName) +{ + for (size_t i = 0; i < hostName.size(); ++i) + { + char ch_data = *(hostName.data()); + if (!((ch_data >= '0' && ch_data <= '9') || (ch_data >= 'A' && ch_data <= 'F') || (ch_data >= 'a' && ch_data <= 'f'))) + { + return false; + } + } + return true; +} + +bool IsMdnsBroadcastPacket(const IPPacketInfo & pktInfo, const System::PacketBufferHandle & pktPayload) +{ + // if the packet is not a broadcast packet to mDNS port, drop it. + VerifyOrReturnValue(pktInfo.DestPort == 5353, false); +#if INET_CONFIG_ENABLE_IPV4 + ip_addr_t mdnsIPv4BroadcastAddr = IPADDR4_INIT_BYTES(224, 0, 0, 251); + if (pktInfo.DestAddress == Inet::IPAddress(mdnsIPv4BroadcastAddr)) + { + return true; + } +#endif + ip_addr_t mdnsIPv6BroadcastAddr = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0xFB); + if (pktInfo.DestAddress == Inet::IPAddress(mdnsIPv6BroadcastAddr)) + { + return true; + } + return false; +} + +bool PayloadContainsCaseInsensitive(const System::PacketBufferHandle & payload, const Span & pattern) +{ + if (payload->TotalLength() == 0 || pattern.size() == 0) + { + return false; + } + + if (payload->HasChainedBuffer() || payload->TotalLength() < pattern.size()) + { + return false; + } + + Span payloadView(payload->Start(), payload->TotalLength()); + + auto toLower = [](unsigned char c) { return std::tolower(c); }; + + auto it = std::search(payloadView.begin(), payloadView.end(), pattern.begin(), pattern.end(), + [&](unsigned char a, unsigned char b) { return toLower(a) == toLower(b); }); + + return (it != payloadView.end()); +} + +} // namespace + +FilterOutcome HostNameFilter::Filter(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload) +{ + // Drop the mDNS packets which don't contain 'matter' or ''. + const unsigned char matterBytes[] = { 'm', 'a', 't', 't', 'e', 'r' }; + if (PayloadContainsCaseInsensitive(pktPayload, Span(matterBytes)) || + PayloadContainsCaseInsensitive(pktPayload, Span(mHostName))) + { + return FilterOutcome::kAllowPacket; + } + return FilterOutcome::kDropPacket; +} + +CHIP_ERROR HostNameFilter::SetHostName(Span & hostName) +{ + VerifyOrReturnError(IsValidMdnsHostName(hostName), CHIP_ERROR_INVALID_ARGUMENT); + memcpy(mHostName, hostName.data(), hostName.size()); + return CHIP_NO_ERROR; +} + +namespace SilabsEndpointQueueFilter { + +EndpointQueueFilter::EndpointQueueFilter() : mTooManyFilter(mConfig.allowedQueuedPackets) {} + +EndpointQueueFilter::EndpointQueueFilter(size_t maxAllowedQueuedPackets) : mTooManyFilter(maxAllowedQueuedPackets) {} + +FilterOutcome EndpointQueueFilter::FilterBeforeEnqueue(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload) +{ + VerifyOrReturnError(FilterOutcome::kAllowPacket == mTooManyFilter.FilterBeforeEnqueue(endpoint, pktInfo, pktPayload), + FilterOutcome::kDropPacket); + + if (!IsMdnsBroadcastPacket(pktInfo, pktPayload)) + { + return FilterOutcome::kAllowPacket; + } + return mHostNameFilter.Filter(endpoint, pktInfo, pktPayload); +} + +FilterOutcome EndpointQueueFilter::FilterAfterDequeue(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload) +{ + return mTooManyFilter.FilterAfterDequeue(endpoint, pktInfo, pktPayload); +} + +} // namespace SilabsEndpointQueueFilter +} // namespace Inet +} // namespace chip diff --git a/src/platform/silabs/EndpointQueueFilter.h b/src/platform/silabs/EndpointQueueFilter.h new file mode 100644 index 00000000000000..779fcab6951dfa --- /dev/null +++ b/src/platform/silabs/EndpointQueueFilter.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace Inet { + +struct EndpointFilter +{ + virtual ~EndpointFilter() = default; + virtual EndpointQueueFilter::FilterOutcome Filter(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload) = 0; +}; + +struct EndpointQueueFilterConfig +{ + size_t allowedQueuedPackets = 10; // Default value +}; + +struct HostNameFilter : EndpointFilter +{ + static constexpr size_t kHostNameLengthMax = 13; // 6 bytes in hex and null terminator. + + EndpointQueueFilter::FilterOutcome Filter(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload) override; + + CHIP_ERROR SetHostName(Span & name); + +private: + uint8_t mHostName[kHostNameLengthMax] = { 0 }; + static constexpr size_t kMdnsPort = 5353; +}; + +namespace SilabsEndpointQueueFilter { + +class EndpointQueueFilter : public Inet::EndpointQueueFilter +{ +public: + EndpointQueueFilterConfig mConfig; + EndpointQueueFilter(); + EndpointQueueFilter(size_t maxAllowedQueuedPackets); + + FilterOutcome FilterBeforeEnqueue(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload) override; + + FilterOutcome FilterAfterDequeue(const void * endpoint, const IPPacketInfo & pktInfo, + const System::PacketBufferHandle & pktPayload); + + CHIP_ERROR SetHostName(Span & addr) { return mHostNameFilter.SetHostName(addr); } + + // Method to set the configuration + void SetConfig(const EndpointQueueFilterConfig & config) { mConfig = config; } + +private: + DropIfTooManyQueuedPacketsFilter mTooManyFilter; + HostNameFilter mHostNameFilter; +}; + +} // namespace SilabsEndpointQueueFilter +} // namespace Inet +} // namespace chip diff --git a/src/platform/silabs/SiWx917/BUILD.gn b/src/platform/silabs/SiWx917/BUILD.gn index 826d8accd974d7..c9ba550275f7e8 100644 --- a/src/platform/silabs/SiWx917/BUILD.gn +++ b/src/platform/silabs/SiWx917/BUILD.gn @@ -52,6 +52,8 @@ static_library("SiWx917") { "${silabs_platform_dir}/ConnectivityManagerImpl_WIFI.cpp", "${silabs_platform_dir}/DiagnosticDataProviderImpl.cpp", "${silabs_platform_dir}/DiagnosticDataProviderImpl.h", + "${silabs_platform_dir}/EndpointQueueFilter.cpp", + "${silabs_platform_dir}/EndpointQueueFilter.h", "${silabs_platform_dir}/InetPlatformConfig.h", "${silabs_platform_dir}/KeyValueStoreManagerImpl.cpp", "${silabs_platform_dir}/KeyValueStoreManagerImpl.h", diff --git a/src/platform/silabs/efr32/BUILD.gn b/src/platform/silabs/efr32/BUILD.gn index f39628d4845726..e0f3e3820a425e 100644 --- a/src/platform/silabs/efr32/BUILD.gn +++ b/src/platform/silabs/efr32/BUILD.gn @@ -158,6 +158,8 @@ static_library("efr32") { if (chip_enable_wifi) { sources += [ "${silabs_platform_dir}/ConnectivityManagerImpl_WIFI.cpp", + "${silabs_platform_dir}/EndpointQueueFilter.cpp", + "${silabs_platform_dir}/EndpointQueueFilter.h", "${silabs_platform_dir}/NetworkCommissioningWiFiDriver.cpp", "${silabs_platform_dir}/NetworkCommissioningWiFiDriver.h", ]