diff --git a/src/platform/Linux/ConfigurationManagerImpl.cpp b/src/platform/Linux/ConfigurationManagerImpl.cpp index e3710959e5a6f1..44e77e4e290ebe 100644 --- a/src/platform/Linux/ConfigurationManagerImpl.cpp +++ b/src/platform/Linux/ConfigurationManagerImpl.cpp @@ -23,8 +23,6 @@ * for Linux platforms. */ -#include - #include #include #include diff --git a/src/platform/Tizen/ConfigurationManagerImpl.cpp b/src/platform/Tizen/ConfigurationManagerImpl.cpp index 961df4130d4603..9d56863167076a 100644 --- a/src/platform/Tizen/ConfigurationManagerImpl.cpp +++ b/src/platform/Tizen/ConfigurationManagerImpl.cpp @@ -29,14 +29,16 @@ #include #include #include +#include +#include -#include "PosixConfig.h" #include "WiFiManager.h" -#include "platform/internal/GenericConfigurationManagerImpl.ipp" namespace chip { namespace DeviceLayer { +using namespace ::chip::DeviceLayer::Internal; + ConfigurationManagerImpl & ConfigurationManagerImpl::GetDefaultInstance() { static ConfigurationManagerImpl sInstance; @@ -175,6 +177,26 @@ void ConfigurationManagerImpl::RunConfigUnitTest() Internal::PosixConfig::RunConfigUnitTest(); } +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + return ReadConfigValue(PosixConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return WriteConfigValue(PosixConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::GetBootReason(uint32_t & bootReason) +{ + return ReadConfigValue(PosixConfig::kCounterKey_BootReason, bootReason); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreBootReason(uint32_t bootReason) +{ + return WriteConfigValue(PosixConfig::kCounterKey_BootReason, bootReason); +} + ConfigurationManager & ConfigurationMgrImpl() { return ConfigurationManagerImpl::GetDefaultInstance(); diff --git a/src/platform/Tizen/ConfigurationManagerImpl.h b/src/platform/Tizen/ConfigurationManagerImpl.h index ee9ddc5b427b07..e7f5d9d3b65c3b 100644 --- a/src/platform/Tizen/ConfigurationManagerImpl.h +++ b/src/platform/Tizen/ConfigurationManagerImpl.h @@ -46,6 +46,11 @@ class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImp CHIP_ERROR StoreVendorId(uint16_t vendorId); CHIP_ERROR StoreProductId(uint16_t productId); + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours) override; + CHIP_ERROR GetBootReason(uint32_t & bootReason) override; + CHIP_ERROR StoreBootReason(uint32_t bootReason) override; + // This returns an instance of this class. static ConfigurationManagerImpl & GetDefaultInstance(); diff --git a/src/platform/Tizen/ConnectivityManagerImpl.cpp b/src/platform/Tizen/ConnectivityManagerImpl.cpp index a954b6b7e0fbfc..9000ee710c0664 100644 --- a/src/platform/Tizen/ConnectivityManagerImpl.cpp +++ b/src/platform/Tizen/ConnectivityManagerImpl.cpp @@ -34,6 +34,8 @@ #include #include #include +#include + #include #include @@ -55,15 +57,32 @@ #include "WiFiManager.h" #endif +using namespace ::chip::DeviceLayer::Internal; +using namespace ::chip::app::Clusters::WiFiNetworkDiagnostics; + namespace chip { namespace DeviceLayer { ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI +char ConnectivityManagerImpl::sWiFiIfName[]; +#endif + CHIP_ERROR ConnectivityManagerImpl::_Init() { CHIP_ERROR err = CHIP_NO_ERROR; + if (ConnectivityUtils::GetEthInterfaceName(mEthIfName, IFNAMSIZ) == CHIP_NO_ERROR) + { + ChipLogProgress(DeviceLayer, "Got Ethernet interface: %s", mEthIfName); + } + else + { + ChipLogError(DeviceLayer, "Failed to get Ethernet interface"); + mEthIfName[0] = '\0'; + } + #if CHIP_DEVICE_CONFIG_ENABLE_WIFI mWiFiStationMode = kWiFiStationMode_Disabled; mWiFiAPMode = kWiFiAPMode_Disabled; @@ -73,6 +92,16 @@ CHIP_ERROR ConnectivityManagerImpl::_Init() mWiFiAPIdleTimeout = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_WIFI_AP_IDLE_TIMEOUT); Internal::WiFiMgr().Init(); + + if (ConnectivityUtils::GetWiFiInterfaceName(sWiFiIfName, IFNAMSIZ) == CHIP_NO_ERROR) + { + ChipLogProgress(DeviceLayer, "Got WiFi interface: %s", sWiFiIfName); + } + else + { + ChipLogError(DeviceLayer, "Failed to get WiFi interface"); + sWiFiIfName[0] = '\0'; + } #endif return err; @@ -224,6 +253,59 @@ bool ConnectivityManagerImpl::IsWiFiManagementStarted() return isActivated; } +CHIP_ERROR ConnectivityManagerImpl::GetWiFiBssId(MutableByteSpan & value) +{ + constexpr size_t bssIdSize = 6; + VerifyOrReturnError(value.size() >= bssIdSize, CHIP_ERROR_BUFFER_TOO_SMALL); + + uint8_t * bssId = nullptr; + CHIP_ERROR err = Internal::WiFiMgr().GetBssId(bssId); + ReturnErrorOnFailure(err); + + memcpy(value.data(), bssId, bssIdSize); + value.reduce_size(bssIdSize); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConnectivityManagerImpl::GetWiFiSecurityType(SecurityTypeEnum & securityType) +{ + wifi_manager_security_type_e secType; + CHIP_ERROR err = Internal::WiFiMgr().GetSecurityType(&secType); + ReturnErrorOnFailure(err); + + switch (secType) + { + case WIFI_MANAGER_SECURITY_TYPE_NONE: + securityType = SecurityTypeEnum::kNone; + break; + case WIFI_MANAGER_SECURITY_TYPE_WEP: + securityType = SecurityTypeEnum::kWep; + break; + case WIFI_MANAGER_SECURITY_TYPE_WPA_PSK: + securityType = SecurityTypeEnum::kWpa; + break; + case WIFI_MANAGER_SECURITY_TYPE_WPA2_PSK: + securityType = SecurityTypeEnum::kWpa2; + break; + case WIFI_MANAGER_SECURITY_TYPE_EAP: + case WIFI_MANAGER_SECURITY_TYPE_WPA_FT_PSK: + case WIFI_MANAGER_SECURITY_TYPE_SAE: + case WIFI_MANAGER_SECURITY_TYPE_OWE: + case WIFI_MANAGER_SECURITY_TYPE_DPP: + default: + securityType = SecurityTypeEnum::kUnspecified; + break; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConnectivityManagerImpl::GetWiFiVersion(WiFiVersionEnum & wiFiVersion) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI } // namespace DeviceLayer diff --git a/src/platform/Tizen/ConnectivityManagerImpl.h b/src/platform/Tizen/ConnectivityManagerImpl.h index 32edbc146c9b0e..04d692a1f05f8f 100644 --- a/src/platform/Tizen/ConnectivityManagerImpl.h +++ b/src/platform/Tizen/ConnectivityManagerImpl.h @@ -87,8 +87,14 @@ class ConnectivityManagerImpl final : public ConnectivityManager, void StartWiFiManagement(); void StopWiFiManagement(); bool IsWiFiManagementStarted(); + CHIP_ERROR GetWiFiBssId(MutableByteSpan & value); + CHIP_ERROR GetWiFiSecurityType(app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum & securityType); + CHIP_ERROR GetWiFiVersion(app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum & wiFiVersion); + const char * GetWiFiIfName() { return (sWiFiIfName[0] == '\0') ? nullptr : sWiFiIfName; } #endif + const char * GetEthernetIfName() { return (mEthIfName[0] == '\0') ? nullptr : mEthIfName; } + private: // ===== Members that implement the ConnectivityManager abstract interface. @@ -127,6 +133,8 @@ class ConnectivityManagerImpl final : public ConnectivityManager, // ===== Private members reserved for use by this class only. + char mEthIfName[IFNAMSIZ]; + #if CHIP_DEVICE_CONFIG_ENABLE_WIFI ConnectivityManager::WiFiStationMode mWiFiStationMode; ConnectivityManager::WiFiAPMode mWiFiAPMode; @@ -134,6 +142,7 @@ class ConnectivityManagerImpl final : public ConnectivityManager, System::Clock::Timestamp mLastAPDemandTime; System::Clock::Timeout mWiFiStationReconnectInterval; System::Clock::Timeout mWiFiAPIdleTimeout; + static char sWiFiIfName[IFNAMSIZ]; #endif }; diff --git a/src/platform/Tizen/ConnectivityUtils.cpp b/src/platform/Tizen/ConnectivityUtils.cpp index 4a1f94e5c7453e..c5aa2437adbb60 100644 --- a/src/platform/Tizen/ConnectivityUtils.cpp +++ b/src/platform/Tizen/ConnectivityUtils.cpp @@ -17,14 +17,11 @@ #include "ConnectivityUtils.h" -// XXX: This is a workaround for a bug in the Tizen SDK header files. It is not -// possible to include both and at the same time. -// This will cause warning that struct ifmap is redefined. On Linux, this -// is not a problem, because in the struct is guarded with -// ifdef. To prevent this, we will define _LINUX_IF_H, so the -// will not be included. -#define _LINUX_IF_H +#include +#include +#include +#include #include #include #include @@ -35,19 +32,50 @@ #include -#include #include #include +using namespace ::chip::app::Clusters::GeneralDiagnostics; +using namespace ::chip::app::Clusters::EthernetNetworkDiagnostics; + namespace chip { namespace DeviceLayer { namespace Internal { -app::Clusters::GeneralDiagnostics::InterfaceTypeEnum ConnectivityUtils::GetInterfaceConnectionType(const char * ifname) +uint16_t ConnectivityUtils::MapChannelToFrequency(const uint16_t inBand, const uint8_t inChannel) +{ + uint16_t frequency = 0; + + if (inBand == kWiFi_BAND_2_4_GHZ) + { + frequency = Map2400MHz(inChannel); + } + else if (inBand == kWiFi_BAND_5_0_GHZ) + { + frequency = Map5000MHz(inChannel); + } + + return frequency; +} + +uint8_t ConnectivityUtils::MapFrequencyToChannel(const uint16_t frequency) +{ + if (frequency < 2412) + return 0; + + if (frequency < 2484) + return static_cast((frequency - 2407) / 5); + + if (frequency == 2484) + return 14; + + return static_cast(frequency / 5 - 1000); +} + +InterfaceTypeEnum ConnectivityUtils::GetInterfaceConnectionType(const char * ifname) { - app::Clusters::GeneralDiagnostics::InterfaceTypeEnum ret = - app::Clusters::GeneralDiagnostics::InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_UNSPECIFIED; - int sock = -1; + InterfaceTypeEnum ret = InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_UNSPECIFIED; + int sock = -1; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { @@ -61,7 +89,7 @@ app::Clusters::GeneralDiagnostics::InterfaceTypeEnum ConnectivityUtils::GetInter if (ioctl(sock, SIOCGIWNAME, &pwrq) != -1) { - ret = app::Clusters::GeneralDiagnostics::InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_WI_FI; + ret = InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_WI_FI; } else if ((strncmp(ifname, "en", 2) == 0) || (strncmp(ifname, "eth", 3) == 0)) { @@ -72,7 +100,7 @@ app::Clusters::GeneralDiagnostics::InterfaceTypeEnum ConnectivityUtils::GetInter Platform::CopyString(ifr.ifr_name, ifname); if (ioctl(sock, SIOCETHTOOL, &ifr) != -1) - ret = app::Clusters::GeneralDiagnostics::InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_ETHERNET; + ret = InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_ETHERNET; } close(sock); @@ -80,6 +108,607 @@ app::Clusters::GeneralDiagnostics::InterfaceTypeEnum ConnectivityUtils::GetInter return ret; } +CHIP_ERROR ConnectivityUtils::GetInterfaceHardwareAddrs(const char * ifname, uint8_t * buf, size_t bufSize) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + int skfd; + + if (ifname[0] == '\0') + { + ChipLogError(DeviceLayer, "Invalid argument for interface name"); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + struct ifreq req; + Platform::CopyString(req.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFHWADDR, &req) != -1) + { + // Copy 48-bit IEEE MAC Address + VerifyOrReturnError(bufSize >= 6, CHIP_ERROR_BUFFER_TOO_SMALL); + + memset(buf, 0, bufSize); + memcpy(buf, req.ifr_ifru.ifru_hwaddr.sa_data, 6); + err = CHIP_NO_ERROR; + } + + close(skfd); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetInterfaceIPv4Addrs(const char * ifname, uint8_t & size, NetworkInterface * ifp) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + uint8_t index = 0; + for (struct ifaddrs * ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) + { + if (strcmp(ifname, ifa->ifa_name) == 0) + { + void * addPtr = &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; + + memcpy(ifp->Ipv4AddressesBuffer[index], addPtr, kMaxIPv4AddrSize); + ifp->Ipv4AddressSpans[index] = ByteSpan(ifp->Ipv4AddressesBuffer[index], kMaxIPv4AddrSize); + index++; + + if (index >= kMaxIPv4AddrCount) + { + break; + } + } + } + } + + if (index > 0) + { + err = CHIP_NO_ERROR; + size = index; + } + + freeifaddrs(ifaddr); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetInterfaceIPv6Addrs(const char * ifname, uint8_t & size, NetworkInterface * ifp) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + uint8_t index = 0; + for (struct ifaddrs * ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) + { + if (strcmp(ifname, ifa->ifa_name) == 0) + { + void * addPtr = &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr; + + memcpy(ifp->Ipv6AddressesBuffer[index], addPtr, kMaxIPv6AddrSize); + ifp->Ipv6AddressSpans[index] = ByteSpan(ifp->Ipv6AddressesBuffer[index], kMaxIPv6AddrSize); + index++; + + if (index >= kMaxIPv6AddrCount) + { + break; + } + } + } + } + + if (index > 0) + { + err = CHIP_NO_ERROR; + size = index; + } + + freeifaddrs(ifaddr); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiInterfaceName(char * ifname, size_t bufSize) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + struct ifaddrs * ifa = nullptr; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (GetInterfaceConnectionType(ifa->ifa_name) == InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_WI_FI) + { + Platform::CopyString(ifname, bufSize, ifa->ifa_name); + err = CHIP_NO_ERROR; + break; + } + } + + freeifaddrs(ifaddr); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiChannelNumber(const char * ifname, uint16_t & channelNumber) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct iwreq wrq; + int skfd; + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + if ((err = GetWiFiParameter(skfd, ifname, SIOCGIWFREQ, &wrq)) == CHIP_NO_ERROR) + { + double freq = ConvertFrequenceToFloat(&(wrq.u.freq)); + VerifyOrReturnError((freq / 1000000) <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + channelNumber = MapFrequencyToChannel(static_cast(freq / 1000000)); + + err = CHIP_NO_ERROR; + } + else + { + ChipLogError(DeviceLayer, "Failed to get channel/frequency (Hz).") + } + + close(skfd); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiRssi(const char * ifname, int8_t & rssi) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct iw_statistics stats; + int skfd; + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + if ((err = GetWiFiStats(skfd, ifname, &stats)) == CHIP_NO_ERROR) + { + struct iw_quality * qual = &stats.qual; + + if (qual->updated & IW_QUAL_RCPI) + { + /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */ + if (!(qual->updated & IW_QUAL_LEVEL_INVALID)) + { + double rcpilevel = (qual->level / 2.0) - 110.0; + VerifyOrReturnError(rcpilevel <= INT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rssi = static_cast(rcpilevel); + err = CHIP_NO_ERROR; + } + } + else + { + if (qual->updated & IW_QUAL_DBM) + { + if (!(qual->updated & IW_QUAL_LEVEL_INVALID)) + { + int dblevel = qual->level; + /* dBm[-192; 63] */ + if (qual->level >= 64) + dblevel -= 0x100; + + VerifyOrReturnError(dblevel <= INT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rssi = static_cast(dblevel); + err = CHIP_NO_ERROR; + } + } + else + { + if (!(qual->updated & IW_QUAL_LEVEL_INVALID)) + { + VerifyOrReturnError(qual->level <= INT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rssi = static_cast(qual->level); + err = CHIP_NO_ERROR; + } + } + } + } + else + { + ChipLogError(DeviceLayer, "Failed to get /proc/net/wireless stats.") + } + + close(skfd); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiBeaconLostCount(const char * ifname, uint32_t & beaconLostCount) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct iw_statistics stats; + int skfd; + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + if (GetWiFiStats(skfd, ifname, &stats) == CHIP_NO_ERROR) + { + beaconLostCount = stats.miss.beacon; + err = CHIP_NO_ERROR; + } + + close(skfd); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiCurrentMaxRate(const char * ifname, uint64_t & currentMaxRate) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct iwreq wrq; + int skfd; + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + if ((err = GetWiFiParameter(skfd, ifname, SIOCGIWRATE, &wrq)) == CHIP_NO_ERROR) + { + currentMaxRate = wrq.u.bitrate.value; + err = CHIP_NO_ERROR; + } + else + { + ChipLogError(DeviceLayer, "Failed to get channel/frequency (Hz).") + } + + close(skfd); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetEthInterfaceName(char * ifname, size_t bufSize) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + struct ifaddrs * ifa = nullptr; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (GetInterfaceConnectionType(ifa->ifa_name) == InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_ETHERNET) + { + Platform::CopyString(ifname, bufSize, ifa->ifa_name); + err = CHIP_NO_ERROR; + break; + } + } + + freeifaddrs(ifaddr); + return err; +} + +CHIP_ERROR ConnectivityUtils::GetEthPHYRate(const char * ifname, PHYRateEnum & pHYRate) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + int skfd; + uint32_t speed = 0; + struct ethtool_cmd ecmd = {}; + ecmd.cmd = ETHTOOL_GSET; + struct ifreq ifr = {}; + + ifr.ifr_data = reinterpret_cast(&ecmd); + Platform::CopyString(ifr.ifr_name, ifname); + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1) + { + ChipLogError(DeviceLayer, "Cannot get device settings"); + close(skfd); + return CHIP_ERROR_READ_FAILED; + } + + speed = (ecmd.speed_hi << 16) | ecmd.speed; + switch (speed) + { + case 10: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE10_M; + break; + case 100: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE100_M; + break; + case 1000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE1_G; + break; + case 25000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE2_5_G; + break; + case 5000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE5_G; + break; + case 10000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE10_G; + break; + case 40000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE40_G; + break; + case 100000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE100_G; + break; + case 200000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE200_G; + break; + case 400000: + pHYRate = EmberAfPHYRateEnum::EMBER_ZCL_PHY_RATE_ENUM_RATE400_G; + break; + default: + ChipLogError(DeviceLayer, "Undefined speed! (%d)\n", speed); + err = CHIP_ERROR_READ_FAILED; + break; + }; + + close(skfd); + + return err; +} + +CHIP_ERROR ConnectivityUtils::GetEthFullDuplex(const char * ifname, bool & fullDuplex) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + + int skfd; + struct ethtool_cmd ecmd = {}; + ecmd.cmd = ETHTOOL_GSET; + struct ifreq ifr = {}; + + ifr.ifr_data = reinterpret_cast(&ecmd); + Platform::CopyString(ifr.ifr_name, ifname); + + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + ChipLogError(DeviceLayer, "Failed to create a channel to the NET kernel."); + return CHIP_ERROR_OPEN_FAILED; + } + + if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1) + { + ChipLogError(DeviceLayer, "Cannot get device settings"); + err = CHIP_ERROR_READ_FAILED; + } + else + { + fullDuplex = ecmd.duplex == DUPLEX_FULL; + err = CHIP_NO_ERROR; + } + + close(skfd); + + return err; +} + +uint16_t ConnectivityUtils::Map2400MHz(const uint8_t inChannel) +{ + uint16_t frequency = 0; + + if (inChannel >= 1 && inChannel <= 13) + { + frequency = static_cast(2412 + ((inChannel - 1) * 5)); + } + else if (inChannel == 14) + { + frequency = 2484; + } + + return frequency; +} + +uint16_t ConnectivityUtils::Map5000MHz(const uint8_t inChannel) +{ + uint16_t frequency = 0; + + switch (inChannel) + { + case 183: + frequency = 4915; + break; + case 184: + frequency = 4920; + break; + case 185: + frequency = 4925; + break; + case 187: + frequency = 4935; + break; + case 188: + frequency = 4940; + break; + case 189: + frequency = 4945; + break; + case 192: + frequency = 4960; + break; + case 196: + frequency = 4980; + break; + case 7: + frequency = 5035; + break; + case 8: + frequency = 5040; + break; + case 9: + frequency = 5045; + break; + case 11: + frequency = 5055; + break; + case 12: + frequency = 5060; + break; + case 16: + frequency = 5080; + break; + case 34: + frequency = 5170; + break; + case 36: + frequency = 5180; + break; + case 38: + frequency = 5190; + break; + case 40: + frequency = 5200; + break; + case 42: + frequency = 5210; + break; + case 44: + frequency = 5220; + break; + case 46: + frequency = 5230; + break; + case 48: + frequency = 5240; + break; + case 52: + frequency = 5260; + break; + case 56: + frequency = 5280; + break; + case 60: + frequency = 5300; + break; + case 64: + frequency = 5320; + break; + case 100: + frequency = 5500; + break; + case 104: + frequency = 5520; + break; + case 108: + frequency = 5540; + break; + case 112: + frequency = 5560; + break; + case 116: + frequency = 5580; + break; + case 120: + frequency = 5600; + break; + case 124: + frequency = 5620; + break; + case 128: + frequency = 5640; + break; + case 132: + frequency = 5660; + break; + case 136: + frequency = 5680; + break; + case 140: + frequency = 5700; + break; + case 149: + frequency = 5745; + break; + case 153: + frequency = 5765; + break; + case 157: + frequency = 5785; + break; + case 161: + frequency = 5805; + break; + case 165: + frequency = 5825; + break; + } + + return frequency; +} + +double ConnectivityUtils::ConvertFrequenceToFloat(const iw_freq * in) +{ + double result = (double) in->m; + + for (int i = 0; i < in->e; i++) + result *= 10; + + return result; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiParameter(int skfd, /* Socket to the kernel */ + const char * ifname, /* Device name */ + int request, /* WE ID */ + struct iwreq * pwrq) /* Fixed part of the request */ +{ + Platform::CopyString(pwrq->ifr_name, ifname); + + if (ioctl(skfd, request, pwrq) < 0) + return CHIP_ERROR_BAD_REQUEST; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ConnectivityUtils::GetWiFiStats(int skfd, const char * ifname, struct iw_statistics * stats) +{ + struct iwreq wrq; + + wrq.u.data.pointer = (caddr_t) stats; + wrq.u.data.length = sizeof(struct iw_statistics); + wrq.u.data.flags = 1; /*Clear updated flag */ + Platform::CopyString(wrq.ifr_name, ifname); + + return GetWiFiParameter(skfd, ifname, SIOCGIWSTATS, &wrq); +} + } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Tizen/ConnectivityUtils.h b/src/platform/Tizen/ConnectivityUtils.h index 16fb18268d8a79..a292b5f2ae682a 100644 --- a/src/platform/Tizen/ConnectivityUtils.h +++ b/src/platform/Tizen/ConnectivityUtils.h @@ -17,18 +17,51 @@ #pragma once -#include +#include +#include -#include "platform/internal/CHIPDeviceLayerInternal.h" +// XXX: This is a workaround for a bug in the Tizen SDK header files. It is not +// possible to include both and at the same time. +// This will cause warning that struct ifmap is redefined. On Linux, this +// is not a problem, because in the struct is guarded with +// ifdef. To prevent this, we will define _LINUX_IF_H, so the +// will not be included. +#define _LINUX_IF_H + +#include +#include namespace chip { namespace DeviceLayer { namespace Internal { +static constexpr uint16_t kWiFi_BAND_2_4_GHZ = 2400; +static constexpr uint16_t kWiFi_BAND_5_0_GHZ = 5000; + class ConnectivityUtils { public: + static uint16_t MapChannelToFrequency(const uint16_t inBand, const uint8_t inChannel); + static uint8_t MapFrequencyToChannel(const uint16_t frequency); static app::Clusters::GeneralDiagnostics::InterfaceTypeEnum GetInterfaceConnectionType(const char * ifname); + static CHIP_ERROR GetInterfaceHardwareAddrs(const char * ifname, uint8_t * buf, size_t bufSize); + static CHIP_ERROR GetInterfaceIPv4Addrs(const char * ifname, uint8_t & size, NetworkInterface * ifp); + static CHIP_ERROR GetInterfaceIPv6Addrs(const char * ifname, uint8_t & size, NetworkInterface * ifp); + static CHIP_ERROR GetWiFiInterfaceName(char * ifname, size_t bufSize); + static CHIP_ERROR GetWiFiChannelNumber(const char * ifname, uint16_t & channelNumber); + static CHIP_ERROR GetWiFiRssi(const char * ifname, int8_t & rssi); + static CHIP_ERROR GetWiFiBeaconLostCount(const char * ifname, uint32_t & beaconLostCount); + static CHIP_ERROR GetWiFiCurrentMaxRate(const char * ifname, uint64_t & currentMaxRate); + static CHIP_ERROR GetEthInterfaceName(char * ifname, size_t bufSize); + static CHIP_ERROR GetEthPHYRate(const char * ifname, app::Clusters::EthernetNetworkDiagnostics::PHYRateEnum & pHYRate); + static CHIP_ERROR GetEthFullDuplex(const char * ifname, bool & fullDuplex); + +private: + static uint16_t Map2400MHz(const uint8_t inChannel); + static uint16_t Map5000MHz(const uint8_t inChannel); + static double ConvertFrequenceToFloat(const iw_freq * in); + static CHIP_ERROR GetWiFiParameter(int skfd, const char * ifname, int request, struct iwreq * pwrq); + static CHIP_ERROR GetWiFiStats(int skfd, const char * ifname, struct iw_statistics * stats); }; } // namespace Internal diff --git a/src/platform/Tizen/DiagnosticDataProviderImpl.cpp b/src/platform/Tizen/DiagnosticDataProviderImpl.cpp index ad143a4e642269..952cbb46db9ac9 100644 --- a/src/platform/Tizen/DiagnosticDataProviderImpl.cpp +++ b/src/platform/Tizen/DiagnosticDataProviderImpl.cpp @@ -21,9 +21,164 @@ * for Tizen platform. */ -#include "DiagnosticDataProviderImpl.h" +#include +#include #include +#include +#include + +#include +#include +#include + +using namespace ::chip::app; +using namespace ::chip::DeviceLayer::Internal; +using namespace ::chip::app::Clusters::GeneralDiagnostics; + +namespace { + +enum class EthernetStatsCountType +{ + kEthPacketRxCount, + kEthPacketTxCount, + kEthTxErrCount, + kEthCollisionCount, + kEthOverrunCount +}; + +enum class WiFiStatsCountType +{ + kWiFiUnicastPacketRxCount, + kWiFiUnicastPacketTxCount, + kWiFiMulticastPacketRxCount, + kWiFiMulticastPacketTxCount, + kWiFiOverrunCount +}; + +CHIP_ERROR GetEthernetStatsCount(EthernetStatsCountType type, uint64_t & count) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + struct ifaddrs * ifa = nullptr; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == + InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_ETHERNET) + { + ChipLogProgress(DeviceLayer, "Found the primary Ethernet interface:%s", StringOrNullMarker(ifa->ifa_name)); + break; + } + } + + if (ifa != nullptr) + { + if (ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_data != nullptr) + { + struct rtnl_link_stats * stats = (struct rtnl_link_stats *) ifa->ifa_data; + switch (type) + { + case EthernetStatsCountType::kEthPacketRxCount: + count = stats->rx_packets; + err = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthPacketTxCount: + count = stats->tx_packets; + err = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthTxErrCount: + count = stats->tx_errors; + err = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthCollisionCount: + count = stats->collisions; + err = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthOverrunCount: + count = stats->rx_over_errors; + err = CHIP_NO_ERROR; + break; + default: + ChipLogError(DeviceLayer, "Unknown Ethernet statistic metric type"); + break; + } + } + } + + freeifaddrs(ifaddr); + return err; +} + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI +CHIP_ERROR GetWiFiStatsCount(WiFiStatsCountType type, uint64_t & count) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + struct ifaddrs * ifa = nullptr; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_WI_FI) + { + ChipLogProgress(DeviceLayer, "Found the primary WiFi interface:%s", StringOrNullMarker(ifa->ifa_name)); + break; + } + } + + if (ifa != nullptr) + { + if (ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_data != nullptr) + { + struct rtnl_link_stats * stats = (struct rtnl_link_stats *) ifa->ifa_data; + switch (type) + { + case WiFiStatsCountType::kWiFiUnicastPacketRxCount: + count = stats->rx_packets; + err = CHIP_NO_ERROR; + break; + case WiFiStatsCountType::kWiFiUnicastPacketTxCount: + count = stats->tx_packets; + err = CHIP_NO_ERROR; + break; + case WiFiStatsCountType::kWiFiMulticastPacketRxCount: + count = stats->multicast; + err = CHIP_NO_ERROR; + break; + case WiFiStatsCountType::kWiFiMulticastPacketTxCount: + count = 0; + err = CHIP_NO_ERROR; + break; + case WiFiStatsCountType::kWiFiOverrunCount: + count = stats->rx_over_errors; + err = CHIP_NO_ERROR; + break; + default: + ChipLogError(DeviceLayer, "Unknown WiFi statistic metric type"); + break; + } + } + } + + freeifaddrs(ifaddr); + + return err; +} +#endif // #if CHIP_DEVICE_CONFIG_ENABLE_WIFI + +} // namespace namespace chip { namespace DeviceLayer { @@ -34,6 +189,473 @@ DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() return sInstance; } +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree) +{ + struct mallinfo mallocInfo = mallinfo(); + currentHeapFree = mallocInfo.fordblks; + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeapUsed) +{ + struct mallinfo mallocInfo = mallinfo(); + currentHeapUsed = mallocInfo.uordblks; + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR DiagnosticDataProviderImpl::ResetWatermarks() +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetThreadMetrics(ThreadMetrics ** threadMetricsOut) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +void DiagnosticDataProviderImpl::ReleaseThreadMetrics(ThreadMetrics * threadMetrics) {} + +CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetUpTime(uint64_t & upTime) +{ + System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp(); + System::Clock::Timestamp startTime = PlatformMgrImpl().GetStartTime(); + + if (currentTime < startTime) + return CHIP_ERROR_INVALID_TIME; + + upTime = std::chrono::duration_cast(currentTime - startTime).count(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + uint64_t upTime = 0; + + if (GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalHours = 0; + if (ConfigurationMgr().GetTotalOperationalHours(totalHours) == CHIP_NO_ERROR) + { + VerifyOrReturnError(upTime / 3600 <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + totalOperationalHours = totalHours + static_cast(upTime / 3600); + return CHIP_NO_ERROR; + } + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(BootReasonType & bootReason) +{ + uint32_t reason = 0; + + CHIP_ERROR err = ConfigurationMgr().GetBootReason(reason); + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(reason <= UINT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + bootReason = static_cast(reason); + } + + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetActiveHardwareFaults(GeneralFaults & hardwareFaults) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetActiveRadioFaults(GeneralFaults & radioFaults) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetActiveNetworkFaults(GeneralFaults & networkFaults) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp) +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + NetworkInterface * head = nullptr; + for (struct ifaddrs * ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_PACKET) + { + uint8_t size = 0; + NetworkInterface * ifp = new NetworkInterface(); + + Platform::CopyString(ifp->Name, ifa->ifa_name); + + ifp->name = CharSpan::fromCharString(ifp->Name); + ifp->isOperational = ifa->ifa_flags & IFF_RUNNING; + ifp->type = ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name); + ifp->offPremiseServicesReachableIPv4.SetNull(); + ifp->offPremiseServicesReachableIPv6.SetNull(); + + if (ConnectivityUtils::GetInterfaceIPv4Addrs(ifa->ifa_name, size, ifp) == CHIP_NO_ERROR) + { + if (size > 0) + { + ifp->IPv4Addresses = DataModel::List(ifp->Ipv4AddressSpans, size); + } + } + + if (ConnectivityUtils::GetInterfaceIPv6Addrs(ifa->ifa_name, size, ifp) == CHIP_NO_ERROR) + { + if (size > 0) + { + ifp->IPv6Addresses = DataModel::List(ifp->Ipv6AddressSpans, size); + } + } + + if (ConnectivityUtils::GetInterfaceHardwareAddrs(ifa->ifa_name, ifp->MacAddress, kMaxHardwareAddrSize) != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to get network hardware address"); + } + else + { + // Set 48-bit IEEE MAC Address + ifp->hardwareAddress = ByteSpan(ifp->MacAddress, 6); + } + + ifp->Next = head; + head = ifp; + } + } + + *netifpp = head; + err = CHIP_NO_ERROR; + + freeifaddrs(ifaddr); + + return err; +} + +void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp) +{ + while (netifp) + { + NetworkInterface * del = netifp; + netifp = netifp->Next; + delete del; + } +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthPHYRate(app::Clusters::EthernetNetworkDiagnostics::PHYRateEnum & pHYRate) +{ + if (ConnectivityMgrImpl().GetEthernetIfName() == nullptr) + { + return CHIP_ERROR_READ_FAILED; + } + + return ConnectivityUtils::GetEthPHYRate(ConnectivityMgrImpl().GetEthernetIfName(), pHYRate); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthFullDuplex(bool & fullDuplex) +{ + if (ConnectivityMgrImpl().GetEthernetIfName() == nullptr) + { + return CHIP_ERROR_READ_FAILED; + } + + return ConnectivityUtils::GetEthFullDuplex(ConnectivityMgrImpl().GetEthernetIfName(), fullDuplex); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthTimeSinceReset(uint64_t & timeSinceReset) +{ + return GetDiagnosticDataProvider().GetUpTime(timeSinceReset); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthPacketRxCount(uint64_t & packetRxCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetEthernetStatsCount(EthernetStatsCountType::kEthPacketRxCount, count)); + VerifyOrReturnError(count >= mEthPacketRxCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetRxCount = count - mEthPacketRxCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthPacketTxCount(uint64_t & packetTxCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetEthernetStatsCount(EthernetStatsCountType::kEthPacketTxCount, count)); + VerifyOrReturnError(count >= mEthPacketTxCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetTxCount = count - mEthPacketTxCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthTxErrCount(uint64_t & txErrCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetEthernetStatsCount(EthernetStatsCountType::kEthTxErrCount, count)); + VerifyOrReturnError(count >= mEthTxErrCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + txErrCount = count - mEthTxErrCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthCollisionCount(uint64_t & collisionCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetEthernetStatsCount(EthernetStatsCountType::kEthCollisionCount, count)); + VerifyOrReturnError(count >= mEthCollisionCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + collisionCount = count - mEthCollisionCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetEthOverrunCount(uint64_t & overrunCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetEthernetStatsCount(EthernetStatsCountType::kEthOverrunCount, count)); + VerifyOrReturnError(count >= mEthOverrunCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + overrunCount = count - mEthOverrunCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::ResetEthNetworkDiagnosticsCounts() +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + struct ifaddrs * ifa = nullptr; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == + InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_ETHERNET) + { + ChipLogProgress(DeviceLayer, "Found the primary Ethernet interface:%s", StringOrNullMarker(ifa->ifa_name)); + break; + } + } + + if (ifa != nullptr) + { + if (ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_data != nullptr) + { + struct rtnl_link_stats * stats = (struct rtnl_link_stats *) ifa->ifa_data; + + mEthPacketRxCount = stats->rx_packets; + mEthPacketTxCount = stats->tx_packets; + mEthTxErrCount = stats->tx_errors; + mEthCollisionCount = stats->collisions; + mEthOverrunCount = stats->rx_over_errors; + err = CHIP_NO_ERROR; + } + } + + freeifaddrs(ifaddr); + return err; +} + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBssId(MutableByteSpan & bssId) +{ + return ConnectivityMgrImpl().GetWiFiBssId(bssId); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiSecurityType(app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum & securityType) +{ + return ConnectivityMgrImpl().GetWiFiSecurityType(securityType); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiVersion(app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum & wiFiVersion) +{ + return ConnectivityMgrImpl().GetWiFiVersion(wiFiVersion); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiChannelNumber(uint16_t & channelNumber) +{ + if (ConnectivityMgrImpl().GetWiFiIfName() == nullptr) + return CHIP_ERROR_READ_FAILED; + + return ConnectivityUtils::GetWiFiChannelNumber(ConnectivityMgrImpl().GetWiFiIfName(), channelNumber); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiRssi(int8_t & rssi) +{ + if (ConnectivityMgrImpl().GetWiFiIfName() == nullptr) + return CHIP_ERROR_READ_FAILED; + + return ConnectivityUtils::GetWiFiRssi(ConnectivityMgrImpl().GetWiFiIfName(), rssi); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBeaconLostCount(uint32_t & beaconLostCount) +{ + uint32_t count; + + if (ConnectivityMgrImpl().GetWiFiIfName() == nullptr) + return CHIP_ERROR_READ_FAILED; + + ReturnErrorOnFailure(ConnectivityUtils::GetWiFiBeaconLostCount(ConnectivityMgrImpl().GetWiFiIfName(), count)); + VerifyOrReturnError(count >= mBeaconLostCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + beaconLostCount = count - mBeaconLostCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) +{ + if (ConnectivityMgrImpl().GetWiFiIfName() == nullptr) + return CHIP_ERROR_READ_FAILED; + + return ConnectivityUtils::GetWiFiCurrentMaxRate(ConnectivityMgrImpl().GetWiFiIfName(), currentMaxRate); +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetWiFiStatsCount(WiFiStatsCountType::kWiFiMulticastPacketRxCount, count)); + VerifyOrReturnError(count >= mPacketMulticastRxCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + count -= mPacketMulticastRxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetMulticastRxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetWiFiStatsCount(WiFiStatsCountType::kWiFiMulticastPacketTxCount, count)); + VerifyOrReturnError(count >= mPacketMulticastTxCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + count -= mPacketMulticastTxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetMulticastTxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetWiFiStatsCount(WiFiStatsCountType::kWiFiUnicastPacketRxCount, count)); + VerifyOrReturnError(count >= mPacketUnicastRxCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + count -= mPacketUnicastRxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetUnicastRxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetWiFiStatsCount(WiFiStatsCountType::kWiFiUnicastPacketTxCount, count)); + VerifyOrReturnError(count >= mPacketUnicastTxCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + count -= mPacketUnicastTxCount; + VerifyOrReturnError(count <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + + packetUnicastTxCount = static_cast(count); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiOverrunCount(uint64_t & overrunCount) +{ + uint64_t count; + + ReturnErrorOnFailure(GetWiFiStatsCount(WiFiStatsCountType::kWiFiOverrunCount, count)); + VerifyOrReturnError(count >= mOverrunCount, CHIP_ERROR_INVALID_INTEGER_VALUE); + + overrunCount = count - mOverrunCount; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::ResetWiFiNetworkDiagnosticsCounts() +{ + CHIP_ERROR err = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + ReturnErrorOnFailure(GetWiFiBeaconLostCount(mBeaconLostCount)); + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + return err; + } + + struct ifaddrs * ifa = nullptr; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == InterfaceTypeEnum::EMBER_ZCL_INTERFACE_TYPE_ENUM_WI_FI) + { + ChipLogProgress(DeviceLayer, "Found the primary WiFi interface:%s", StringOrNullMarker(ifa->ifa_name)); + break; + } + } + + if (ifa != nullptr) + { + if (ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_data != nullptr) + { + struct rtnl_link_stats * stats = (struct rtnl_link_stats *) ifa->ifa_data; + + mPacketMulticastRxCount = stats->multicast; + mPacketMulticastTxCount = 0; + mPacketUnicastRxCount = stats->rx_packets; + mPacketUnicastTxCount = stats->tx_packets; + mOverrunCount = stats->rx_over_errors; + + err = CHIP_NO_ERROR; + } + } + + freeifaddrs(ifaddr); + return err; +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI + DiagnosticDataProvider & GetDiagnosticDataProviderImpl() { return DiagnosticDataProviderImpl::GetDefaultInstance(); diff --git a/src/platform/Tizen/DiagnosticDataProviderImpl.h b/src/platform/Tizen/DiagnosticDataProviderImpl.h index 1019bc9ec66ab0..80dd3ae7b09a2e 100644 --- a/src/platform/Tizen/DiagnosticDataProviderImpl.h +++ b/src/platform/Tizen/DiagnosticDataProviderImpl.h @@ -28,12 +28,76 @@ namespace chip { namespace DeviceLayer { /** - * Concrete implementation of the PlatformManager singleton object for Linux platforms. + * Concrete implementation of the DiagnosticDataProvider singleton object for Tizen platforms. */ class DiagnosticDataProviderImpl : public DiagnosticDataProvider { public: static DiagnosticDataProviderImpl & GetDefaultInstance(); + + // ===== Methods that implement the DiagnosticDataProvider abstract interface. + + bool SupportsWatermarks() override { return true; } + CHIP_ERROR GetCurrentHeapFree(uint64_t & currentHeapFree) override; + CHIP_ERROR GetCurrentHeapUsed(uint64_t & currentHeapUsed) override; + CHIP_ERROR GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) override; + CHIP_ERROR GetThreadMetrics(ThreadMetrics ** threadMetricsOut) override; + CHIP_ERROR ResetWatermarks() override; + void ReleaseThreadMetrics(ThreadMetrics * threadMetrics) override; + + CHIP_ERROR GetRebootCount(uint16_t & rebootCount) override; + CHIP_ERROR GetUpTime(uint64_t & upTime) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR GetBootReason(BootReasonType & bootReason) override; + + CHIP_ERROR GetActiveHardwareFaults(GeneralFaults & hardwareFaults) override; + CHIP_ERROR GetActiveRadioFaults(GeneralFaults & radioFaults) override; + CHIP_ERROR GetActiveNetworkFaults(GeneralFaults & networkFaults) override; + + CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override; + void ReleaseNetworkInterfaces(NetworkInterface * netifp) override; + + CHIP_ERROR GetEthPHYRate(app::Clusters::EthernetNetworkDiagnostics::PHYRateEnum & pHYRate) override; + CHIP_ERROR GetEthFullDuplex(bool & fullDuplex) override; + CHIP_ERROR GetEthTimeSinceReset(uint64_t & timeSinceReset) override; + CHIP_ERROR GetEthPacketRxCount(uint64_t & packetRxCount) override; + CHIP_ERROR GetEthPacketTxCount(uint64_t & packetTxCount) override; + CHIP_ERROR GetEthTxErrCount(uint64_t & txErrCount) override; + CHIP_ERROR GetEthCollisionCount(uint64_t & collisionCount) override; + CHIP_ERROR GetEthOverrunCount(uint64_t & overrunCount) override; + CHIP_ERROR ResetEthNetworkDiagnosticsCounts() override; + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + CHIP_ERROR GetWiFiBssId(MutableByteSpan & bssId) override; + CHIP_ERROR GetWiFiSecurityType(app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum & securityType) override; + CHIP_ERROR GetWiFiVersion(app::Clusters::WiFiNetworkDiagnostics::WiFiVersionEnum & wiFiVersion) override; + CHIP_ERROR GetWiFiChannelNumber(uint16_t & channelNumber) override; + CHIP_ERROR GetWiFiRssi(int8_t & rssi) override; + CHIP_ERROR GetWiFiBeaconLostCount(uint32_t & beaconLostCount) override; + CHIP_ERROR GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount) override; + CHIP_ERROR GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount) override; + CHIP_ERROR GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount) override; + CHIP_ERROR GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount) override; + CHIP_ERROR GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) override; + CHIP_ERROR GetWiFiOverrunCount(uint64_t & overrunCount) override; + CHIP_ERROR ResetWiFiNetworkDiagnosticsCounts() override; +#endif + +private: + uint64_t mEthPacketRxCount = 0; + uint64_t mEthPacketTxCount = 0; + uint64_t mEthTxErrCount = 0; + uint64_t mEthCollisionCount = 0; + uint64_t mEthOverrunCount = 0; + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + uint32_t mBeaconLostCount = 0; + uint32_t mPacketMulticastRxCount = 0; + uint32_t mPacketMulticastTxCount = 0; + uint32_t mPacketUnicastRxCount = 0; + uint32_t mPacketUnicastTxCount = 0; + uint64_t mOverrunCount = 0; +#endif }; /** diff --git a/src/platform/Tizen/PlatformManagerImpl.cpp b/src/platform/Tizen/PlatformManagerImpl.cpp index d0f62901a61bbe..41e011052742c0 100644 --- a/src/platform/Tizen/PlatformManagerImpl.cpp +++ b/src/platform/Tizen/PlatformManagerImpl.cpp @@ -117,6 +117,8 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack() // earlier, because the generic implementation sets a generic one. SetDeviceInstanceInfoProvider(&DeviceInstanceInfoProviderMgrImpl()); + mStartTime = System::SystemClock().GetMonotonicTimestamp(); + return CHIP_NO_ERROR; } diff --git a/src/platform/Tizen/PlatformManagerImpl.h b/src/platform/Tizen/PlatformManagerImpl.h index 04ad1c02864705..8a3d0e450d9742 100644 --- a/src/platform/Tizen/PlatformManagerImpl.h +++ b/src/platform/Tizen/PlatformManagerImpl.h @@ -66,6 +66,7 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener { return _GLibMatterContextInvokeSync((CHIP_ERROR(*)(void *)) func, (void *) userData); } + System::Clock::Timestamp GetStartTime() { return mStartTime; } private: // ===== Methods that implement the PlatformManager abstract interface. @@ -79,6 +80,8 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener friend PlatformManagerImpl & PlatformMgrImpl(); friend class Internal::BLEManagerImpl; + System::Clock::Timestamp mStartTime = System::Clock::kZero; + static PlatformManagerImpl sInstance; /** diff --git a/src/platform/Tizen/PosixConfig.cpp b/src/platform/Tizen/PosixConfig.cpp index f5c641a2fbc83e..fc65c24bf189a9 100644 --- a/src/platform/Tizen/PosixConfig.cpp +++ b/src/platform/Tizen/PosixConfig.cpp @@ -67,6 +67,11 @@ const PosixConfig::Key PosixConfig::kConfigKey_RegulatoryLocation = { kConfigNam const PosixConfig::Key PosixConfig::kConfigKey_CountryCode = { kConfigNamespace_ChipConfig, "country-code" }; const PosixConfig::Key PosixConfig::kConfigKey_UniqueId = { kConfigNamespace_ChipConfig, "unique-id" }; +// Keys stored in the Chip-counters namespace +const PosixConfig::Key PosixConfig::kCounterKey_TotalOperationalHours = { kConfigNamespace_ChipCounters, + "total-operational-hours" }; +const PosixConfig::Key PosixConfig::kCounterKey_BootReason = { kConfigNamespace_ChipCounters, "boot-reason" }; + CHIP_ERROR PosixConfig::Init() { return CHIP_NO_ERROR; diff --git a/src/platform/Tizen/PosixConfig.h b/src/platform/Tizen/PosixConfig.h index 197adad14e3907..9c5402cadaaf34 100644 --- a/src/platform/Tizen/PosixConfig.h +++ b/src/platform/Tizen/PosixConfig.h @@ -76,6 +76,9 @@ class PosixConfig static const Key kConfigKey_VendorId; static const Key kConfigKey_ProductId; + static const Key kCounterKey_TotalOperationalHours; + static const Key kCounterKey_BootReason; + static CHIP_ERROR Init(void); // Config value accessors. diff --git a/src/platform/Tizen/WiFiManager.cpp b/src/platform/Tizen/WiFiManager.cpp index b45e34bda450c8..b6a8c09be7c22b 100644 --- a/src/platform/Tizen/WiFiManager.cpp +++ b/src/platform/Tizen/WiFiManager.cpp @@ -528,6 +528,33 @@ void WiFiManager::_WiFiSetConnectionState(wifi_manager_connection_state_e connec ChipLogProgress(DeviceLayer, "Set WiFi connection state [%s]", __WiFiConnectionStateToStr(mConnectionState)); } +wifi_manager_ap_h WiFiManager::_WiFiGetConnectedAP() +{ + int wifiErr = WIFI_MANAGER_ERROR_NONE; + wifi_manager_ap_h connectedAp = nullptr; + + wifiErr = wifi_manager_get_connected_ap(mWiFiManagerHandle, &connectedAp); + if (wifiErr == WIFI_MANAGER_ERROR_NONE) + { + char * ssidStr = nullptr; + if (connectedAp != nullptr) + { + wifiErr = wifi_manager_ap_get_essid(connectedAp, &ssidStr); + if (wifiErr != WIFI_MANAGER_ERROR_NONE) + { + ChipLogError(DeviceLayer, "FAIL: get ssid of connected AP [%s]", get_error_message(wifiErr)); + } + } + ChipLogProgress(DeviceLayer, "Get connected AP [%s]", ssidStr); + } + else + { + ChipLogError(DeviceLayer, "FAIL: get connected AP [%s]", get_error_message(wifiErr)); + } + + return connectedAp; +} + wifi_manager_ap_h WiFiManager::_WiFiGetFoundAP() { int wifiErr = WIFI_MANAGER_ERROR_NONE; @@ -798,6 +825,58 @@ CHIP_ERROR WiFiManager::GetConnectionState(wifi_manager_connection_state_e * con return err; } +CHIP_ERROR WiFiManager::GetBssId(uint8_t * bssId) +{ + VerifyOrReturnError(bssId != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + char * bssIdStr = nullptr; + std::unique_ptr _{ bssIdStr, &::free }; + + wifi_manager_ap_h connectedAp = _WiFiGetConnectedAP(); + if (connectedAp == nullptr) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + int wifiErr = wifi_manager_ap_get_bssid(connectedAp, &bssIdStr); + if (wifiErr != WIFI_MANAGER_ERROR_NONE) + { + ChipLogError(DeviceLayer, "FAIL: get bssid [%s]", get_error_message(wifiErr)); + return CHIP_ERROR_READ_FAILED; + } + + if (sscanf(bssIdStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mWiFiBSSID[0], &mWiFiBSSID[1], &mWiFiBSSID[2], &mWiFiBSSID[3], + &mWiFiBSSID[4], &mWiFiBSSID[5]) != 6) + { + ChipLogError(DeviceLayer, "FAIL: parse bssid"); + return CHIP_ERROR_READ_FAILED; + } + + bssId = mWiFiBSSID; + return CHIP_NO_ERROR; +} + +CHIP_ERROR WiFiManager::GetSecurityType(wifi_manager_security_type_e * securityType) +{ + wifi_manager_ap_h connectedAp = _WiFiGetConnectedAP(); + if (connectedAp == nullptr) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + wifi_manager_security_type_e secType; + int wifiErr = wifi_manager_ap_get_security_type(connectedAp, &secType); + if (wifiErr != WIFI_MANAGER_ERROR_NONE) + { + ChipLogError(DeviceLayer, "FAIL: get security type [%s]", get_error_message(wifiErr)); + return CHIP_ERROR_READ_FAILED; + } + + *securityType = secType; + + return CHIP_NO_ERROR; +} + } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Tizen/WiFiManager.h b/src/platform/Tizen/WiFiManager.h index 6304642ed07f51..4ec6dec2e5d7aa 100644 --- a/src/platform/Tizen/WiFiManager.h +++ b/src/platform/Tizen/WiFiManager.h @@ -53,6 +53,8 @@ class WiFiManager CHIP_ERROR SetDeviceState(wifi_manager_device_state_e deviceState); CHIP_ERROR GetModuleState(wifi_manager_module_state_e * moduleState); CHIP_ERROR GetConnectionState(wifi_manager_connection_state_e * connectionState); + CHIP_ERROR GetBssId(uint8_t * bssId); + CHIP_ERROR GetSecurityType(wifi_manager_security_type_e * securityType); private: static void _DeviceStateChangedCb(wifi_manager_device_state_e deviceState, void * userData); @@ -82,6 +84,7 @@ class WiFiManager void _WiFiSetDeviceState(wifi_manager_device_state_e deviceState); void _WiFiSetModuleState(wifi_manager_module_state_e moduleState); void _WiFiSetConnectionState(wifi_manager_connection_state_e connectionState); + wifi_manager_ap_h _WiFiGetConnectedAP(); wifi_manager_ap_h _WiFiGetFoundAP(); friend WiFiManager & WiFiMgr(); @@ -93,6 +96,7 @@ class WiFiManager wifi_manager_module_state_e mModuleState; wifi_manager_connection_state_e mConnectionState; + uint8_t mWiFiBSSID[kWiFiBSSIDLength]; char mWiFiSSID[kMaxWiFiSSIDLength + 1]; char mWiFiKey[kMaxWiFiKeyLength + 1];