| /* |
| * |
| * Copyright (c) 2020-2021 Project CHIP Authors |
| * Copyright (c) 2019 Nest Labs, Inc. |
| * |
| * 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. |
| */ |
| |
| #include <platform/internal/CHIPDeviceLayerInternal.h> |
| |
| #include <platform/ConnectivityManager.h> |
| #include <platform/Linux/ConnectivityUtils.h> |
| #include <platform/internal/BLEManager.h> |
| |
| #include <cstdlib> |
| #include <new> |
| |
| #include <ifaddrs.h> |
| #include <linux/ethtool.h> |
| #include <linux/if_link.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/types.h> |
| |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE |
| #include <platform/internal/GenericConnectivityManagerImpl_BLE.cpp> |
| #endif |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
| #include <platform/internal/GenericConnectivityManagerImpl_Thread.cpp> |
| #endif |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| #include <platform/internal/GenericConnectivityManagerImpl_WiFi.cpp> |
| #endif |
| |
| #ifndef CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD |
| #define CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD "dhclient -nw %s" |
| #endif |
| |
| using namespace ::chip; |
| using namespace ::chip::TLV; |
| using namespace ::chip::DeviceLayer; |
| 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"); |
| } |
| else |
| { |
| struct ifaddrs * ifa = nullptr; |
| |
| /* Walk through linked list, maintaining head pointer so we |
| can free list later */ |
| for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) |
| { |
| if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == InterfaceType::EMBER_ZCL_INTERFACE_TYPE_ETHERNET) |
| { |
| ChipLogProgress(DeviceLayer, "Found the primary Ethernet interface:%s", 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"); |
| } |
| else |
| { |
| struct ifaddrs * ifa = nullptr; |
| |
| /* Walk through linked list, maintaining head pointer so we |
| can free list later */ |
| for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) |
| { |
| if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == InterfaceType::EMBER_ZCL_INTERFACE_TYPE_WI_FI) |
| { |
| ChipLogProgress(DeviceLayer, "Found the primary WiFi interface:%s", ifa->ifa_name); |
| break; |
| } |
| } |
| |
| if (ifa != nullptr) |
| { |
| if (ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_data != nullptr) |
| { |
| // The usecase of this function is embedded devices,on which we can interact with the WiFi |
| // driver to get the accurate number of muticast and unicast packets accurately. |
| // On Linux simulation, we can only get the total packets received, the total bytes transmitted, |
| // the multicast packets received and receiver ring buff overflow. |
| |
| 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 { |
| |
| ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WIFI |
| char ConnectivityManagerImpl::sWiFiIfName[]; |
| #endif |
| |
| CHIP_ERROR ConnectivityManagerImpl::_Init() |
| { |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| mWiFiStationMode = kWiFiStationMode_Disabled; |
| mWiFiStationReconnectInterval = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL); |
| #endif |
| |
| 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 (ResetEthernetStatsCount() != CHIP_NO_ERROR) |
| { |
| ChipLogError(DeviceLayer, "Failed to reset Ethernet statistic counts"); |
| } |
| |
| // Initialize the generic base classes that require it. |
| #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
| GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_Init(); |
| #endif |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WIFI |
| 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'; |
| } |
| |
| if (ResetWiFiStatsCount() != CHIP_NO_ERROR) |
| { |
| ChipLogError(DeviceLayer, "Failed to reset WiFi statistic counts"); |
| } |
| #endif |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) |
| { |
| // Forward the event to the generic base classes as needed. |
| #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
| GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_OnPlatformEvent(event); |
| #endif |
| } |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| |
| BitFlags<Internal::GenericConnectivityManagerImpl_WiFi<ConnectivityManagerImpl>::ConnectivityFlags> |
| ConnectivityManagerImpl::mConnectivityFlag; |
| struct GDBusWpaSupplicant ConnectivityManagerImpl::mWpaSupplicant; |
| std::mutex ConnectivityManagerImpl::mWpaSupplicantMutex; |
| |
| ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode() |
| { |
| if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) |
| { |
| mWiFiStationMode = (mWpaSupplicant.iface != nullptr) ? kWiFiStationMode_Enabled : kWiFiStationMode_Disabled; |
| } |
| |
| return mWiFiStationMode; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode val) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(val != ConnectivityManager::kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); |
| |
| if (mWiFiStationMode != val) |
| { |
| ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode), |
| WiFiStationModeToStr(val)); |
| } |
| |
| mWiFiStationMode = val; |
| exit: |
| return err; |
| } |
| |
| System::Clock::Timeout ConnectivityManagerImpl::_GetWiFiStationReconnectInterval() |
| { |
| return mWiFiStationReconnectInterval; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationReconnectInterval(System::Clock::Timeout val) |
| { |
| mWiFiStationReconnectInterval = val; |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationEnabled() |
| { |
| return GetWiFiStationMode() == kWiFiStationMode_Enabled; |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationConnected() |
| { |
| bool ret = false; |
| const gchar * state = nullptr; |
| |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationConnected: interface not connected"); |
| return false; |
| } |
| |
| state = wpa_fi_w1_wpa_supplicant1_interface_get_state(mWpaSupplicant.iface); |
| if (g_strcmp0(state, "completed") == 0) |
| { |
| mConnectivityFlag.Set(ConnectivityFlags::kHaveIPv4InternetConnectivity) |
| .Set(ConnectivityFlags::kHaveIPv6InternetConnectivity); |
| ret = true; |
| } |
| |
| return ret; |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled() |
| { |
| return mWiFiStationMode == ConnectivityManager::kWiFiStationMode_ApplicationControlled; |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationProvisioned() |
| { |
| bool ret = false; |
| const gchar * bss = nullptr; |
| |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationProvisioned: interface not connected"); |
| return false; |
| } |
| |
| bss = wpa_fi_w1_wpa_supplicant1_interface_get_current_bss(mWpaSupplicant.iface); |
| if (g_str_match_string("BSSs", bss, true)) |
| { |
| ret = true; |
| } |
| |
| return ret; |
| } |
| |
| void ConnectivityManagerImpl::_ClearWiFiStationProvision() |
| { |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: _ClearWiFiStationProvision: interface not connected"); |
| return; |
| } |
| |
| if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) |
| { |
| GError * err = nullptr; |
| wpa_fi_w1_wpa_supplicant1_interface_call_remove_all_networks_sync(mWpaSupplicant.iface, nullptr, &err); |
| |
| if (err != nullptr) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to remove all networks with error: %s", |
| err ? err->message : "unknown error"); |
| g_error_free(err); |
| } |
| } |
| } |
| |
| bool ConnectivityManagerImpl::_CanStartWiFiScan() |
| { |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| bool ret = mWpaSupplicant.state == GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED && |
| mWpaSupplicant.scanState == GDBusWpaSupplicant::WIFI_SCANNING_IDLE; |
| |
| return ret; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(val != kWiFiAPMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); |
| |
| if (mWiFiAPMode != val) |
| { |
| ChipLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val)); |
| mWiFiAPMode = val; |
| |
| DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); |
| } |
| |
| exit: |
| return err; |
| } |
| |
| void ConnectivityManagerImpl::_DemandStartWiFiAP() |
| { |
| if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP"); |
| mLastAPDemandTime = System::SystemClock().GetMonotonicTimestamp(); |
| DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode)); |
| } |
| } |
| |
| void ConnectivityManagerImpl::_StopOnDemandWiFiAP() |
| { |
| if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP"); |
| mLastAPDemandTime = System::Clock::Zero; |
| DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode)); |
| } |
| } |
| |
| void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP() |
| { |
| if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| if (mWiFiAPState == kWiFiAPState_Active) |
| { |
| mLastAPDemandTime = System::SystemClock().GetMonotonicTimestamp(); |
| } |
| } |
| } |
| |
| void ConnectivityManagerImpl::_SetWiFiAPIdleTimeout(System::Clock::Timeout val) |
| { |
| mWiFiAPIdleTimeout = val; |
| DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); |
| } |
| |
| void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data) |
| { |
| GError * err = nullptr; |
| |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| WpaFiW1Wpa_supplicant1Interface * iface = wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus_finish(res, &err); |
| |
| if (mWpaSupplicant.iface) |
| { |
| g_object_unref(mWpaSupplicant.iface); |
| mWpaSupplicant.iface = nullptr; |
| } |
| |
| if (iface != nullptr && err == nullptr) |
| { |
| mWpaSupplicant.iface = iface; |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED; |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant interface proxy"); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant interface proxy %s: %s", |
| mWpaSupplicant.interfacePath, err ? err->message : "unknown error"); |
| |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED; |
| } |
| |
| if (err != nullptr) |
| g_error_free(err); |
| } |
| |
| void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data) |
| { |
| GError * err = nullptr; |
| |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| gboolean result = |
| wpa_fi_w1_wpa_supplicant1_call_get_interface_finish(mWpaSupplicant.proxy, &mWpaSupplicant.interfacePath, res, &err); |
| if (result) |
| { |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH; |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath); |
| |
| wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, |
| mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady, |
| nullptr); |
| } |
| else |
| { |
| GError * error = nullptr; |
| GVariant * args = nullptr; |
| GVariantBuilder builder; |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: can't find interface %s: %s", sWiFiIfName, |
| err ? err->message : "unknown error"); |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: try to create interface %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME); |
| |
| g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); |
| g_variant_builder_add(&builder, "{sv}", "Ifname", g_variant_new_string(CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME)); |
| args = g_variant_builder_end(&builder); |
| |
| result = wpa_fi_w1_wpa_supplicant1_call_create_interface_sync(mWpaSupplicant.proxy, args, &mWpaSupplicant.interfacePath, |
| nullptr, &error); |
| |
| if (result) |
| { |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH; |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath); |
| |
| strncpy(sWiFiIfName, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, IFNAMSIZ); |
| sWiFiIfName[IFNAMSIZ - 1] = '\0'; |
| |
| wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, |
| kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr, |
| _OnWpaInterfaceProxyReady, nullptr); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create interface %s: %s", |
| CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, error ? error->message : "unknown error"); |
| |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH; |
| |
| if (mWpaSupplicant.interfacePath) |
| { |
| g_free(mWpaSupplicant.interfacePath); |
| mWpaSupplicant.interfacePath = nullptr; |
| } |
| } |
| |
| if (error != nullptr) |
| g_error_free(error); |
| } |
| |
| if (err != nullptr) |
| g_error_free(err); |
| } |
| |
| void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, |
| gpointer user_data) |
| { |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| if (mWpaSupplicant.interfacePath) |
| { |
| return; |
| } |
| |
| mWpaSupplicant.interfacePath = const_cast<gchar *>(path); |
| if (mWpaSupplicant.interfacePath) |
| { |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH; |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface added: %s", mWpaSupplicant.interfacePath); |
| |
| wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, |
| mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady, |
| nullptr); |
| } |
| } |
| |
| void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, |
| gpointer user_data) |
| { |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| if (mWpaSupplicant.interfacePath == nullptr) |
| { |
| return; |
| } |
| |
| if (g_strcmp0(mWpaSupplicant.interfacePath, path) == 0) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface removed: %s", path); |
| |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH; |
| |
| if (mWpaSupplicant.interfacePath) |
| { |
| g_free(mWpaSupplicant.interfacePath); |
| mWpaSupplicant.interfacePath = nullptr; |
| } |
| |
| if (mWpaSupplicant.iface) |
| { |
| g_object_unref(mWpaSupplicant.iface); |
| mWpaSupplicant.iface = nullptr; |
| } |
| |
| mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE; |
| } |
| } |
| |
| void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data) |
| { |
| GError * err = nullptr; |
| |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| mWpaSupplicant.proxy = wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus_finish(res, &err); |
| if (mWpaSupplicant.proxy != nullptr && err == nullptr) |
| { |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_CONNECTED; |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant proxy"); |
| |
| g_signal_connect(mWpaSupplicant.proxy, "interface-added", G_CALLBACK(_OnWpaInterfaceAdded), NULL); |
| |
| g_signal_connect(mWpaSupplicant.proxy, "interface-removed", G_CALLBACK(_OnWpaInterfaceRemoved), NULL); |
| |
| wpa_fi_w1_wpa_supplicant1_call_get_interface(mWpaSupplicant.proxy, sWiFiIfName, nullptr, _OnWpaInterfaceReady, nullptr); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant proxy %s", |
| err ? err->message : "unknown error"); |
| mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED; |
| } |
| |
| if (err != nullptr) |
| g_error_free(err); |
| } |
| |
| void ConnectivityManagerImpl::StartWiFiManagement() |
| { |
| mConnectivityFlag.ClearAll(); |
| mWpaSupplicant.state = GDBusWpaSupplicant::INIT; |
| mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE; |
| mWpaSupplicant.proxy = nullptr; |
| mWpaSupplicant.iface = nullptr; |
| mWpaSupplicant.interfacePath = nullptr; |
| mWpaSupplicant.networkPath = nullptr; |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: Start WiFi management"); |
| |
| wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName, |
| kWpaSupplicantObjectPath, nullptr, _OnWpaProxyReady, nullptr); |
| } |
| |
| bool ConnectivityManagerImpl::IsWiFiManagementStarted() |
| { |
| std::lock_guard<std::mutex> lock(mWpaSupplicantMutex); |
| |
| bool ret = mWpaSupplicant.state == GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED; |
| |
| return ret; |
| } |
| |
| void ConnectivityManagerImpl::DriveAPState() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| WiFiAPState targetState; |
| |
| // If the AP interface is not under application control... |
| if (mWiFiAPMode != kWiFiAPMode_ApplicationControlled) |
| { |
| // Determine the target (desired) state for AP interface... |
| |
| // The target state is 'NotActive' if the application has expressly disabled the AP interface. |
| if (mWiFiAPMode == kWiFiAPMode_Disabled) |
| { |
| targetState = kWiFiAPState_NotActive; |
| } |
| |
| // The target state is 'Active' if the application has expressly enabled the AP interface. |
| else if (mWiFiAPMode == kWiFiAPMode_Enabled) |
| { |
| targetState = kWiFiAPState_Active; |
| } |
| |
| // The target state is 'Active' if the AP mode is 'On demand, when no station is available' |
| // and the station interface is not provisioned or the application has disabled the station |
| // interface. |
| else if (mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision && |
| (!IsWiFiStationProvisioned() || GetWiFiStationMode() == kWiFiStationMode_Disabled)) |
| { |
| targetState = kWiFiAPState_Active; |
| } |
| |
| // The target state is 'Active' if the AP mode is one of the 'On demand' modes and there |
| // has been demand for the AP within the idle timeout period. |
| else if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp(); |
| |
| if (mLastAPDemandTime != System::Clock::Zero && now < (mLastAPDemandTime + mWiFiAPIdleTimeout)) |
| { |
| targetState = kWiFiAPState_Active; |
| |
| // Compute the amount of idle time before the AP should be deactivated and |
| // arm a timer to fire at that time. |
| System::Clock::Timeout apTimeout = (mLastAPDemandTime + mWiFiAPIdleTimeout) - now; |
| err = DeviceLayer::SystemLayer().StartTimer(apTimeout, DriveAPState, NULL); |
| SuccessOrExit(err); |
| ChipLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " s", |
| std::chrono::duration_cast<System::Clock::Seconds32>(apTimeout).count()); |
| } |
| else |
| { |
| targetState = kWiFiAPState_NotActive; |
| } |
| } |
| |
| // Otherwise the target state is 'NotActive'. |
| else |
| { |
| targetState = kWiFiAPState_NotActive; |
| } |
| |
| // If the current AP state does not match the target state... |
| if (mWiFiAPState != targetState) |
| { |
| if (targetState == kWiFiAPState_Active) |
| { |
| err = ConfigureWiFiAP(); |
| SuccessOrExit(err); |
| |
| ChangeWiFiAPState(kWiFiAPState_Active); |
| } |
| else |
| { |
| if (mWpaSupplicant.networkPath) |
| { |
| GError * error = nullptr; |
| |
| gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync( |
| mWpaSupplicant.iface, mWpaSupplicant.networkPath, nullptr, &error); |
| |
| if (result) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath); |
| g_free(mWpaSupplicant.networkPath); |
| mWpaSupplicant.networkPath = nullptr; |
| ChangeWiFiAPState(kWiFiAPState_NotActive); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s", |
| error ? error->message : "unknown error"); |
| err = CHIP_ERROR_INTERNAL; |
| } |
| |
| if (error != nullptr) |
| g_error_free(error); |
| } |
| } |
| } |
| } |
| |
| exit: |
| if (err != CHIP_NO_ERROR) |
| { |
| SetWiFiAPMode(kWiFiAPMode_Disabled); |
| ChipLogError(DeviceLayer, "Drive AP state failed: %s", ErrorStr(err)); |
| } |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP() |
| { |
| CHIP_ERROR ret = CHIP_NO_ERROR; |
| GError * err = nullptr; |
| GVariant * args = nullptr; |
| GVariantBuilder builder; |
| |
| uint16_t channel = 1; |
| uint16_t discriminator = 0; |
| char ssid[32]; |
| |
| channel = ConnectivityUtils::MapChannelToFrequency(kWiFi_BAND_2_4_GHZ, CHIP_DEVICE_CONFIG_WIFI_AP_CHANNEL); |
| |
| if (ConfigurationMgr().GetSetupDiscriminator(discriminator) != CHIP_NO_ERROR) |
| discriminator = 0; |
| |
| snprintf(ssid, 32, "%s%04u", CHIP_DEVICE_CONFIG_WIFI_AP_SSID_PREFIX, discriminator); |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: ConfigureWiFiAP, ssid: %s, channel: %d", ssid, channel); |
| |
| // Clean up current network if exists |
| if (mWpaSupplicant.networkPath) |
| { |
| g_object_unref(mWpaSupplicant.networkPath); |
| mWpaSupplicant.networkPath = nullptr; |
| } |
| |
| g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); |
| g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid)); |
| g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("NONE")); |
| g_variant_builder_add(&builder, "{sv}", "mode", g_variant_new_int32(2)); |
| g_variant_builder_add(&builder, "{sv}", "frequency", g_variant_new_int32(channel)); |
| args = g_variant_builder_end(&builder); |
| |
| gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args, |
| &mWpaSupplicant.networkPath, nullptr, &err); |
| |
| if (result) |
| { |
| GError * error = nullptr; |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath); |
| |
| result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath, |
| nullptr, &error); |
| if (result) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: succeeded to start softAP: SSID: %s", ssid); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to start softAP: SSID: %s: %s", ssid, |
| error ? error->message : "unknown error"); |
| |
| ret = CHIP_ERROR_INTERNAL; |
| } |
| |
| if (error != nullptr) |
| g_error_free(error); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error"); |
| |
| if (mWpaSupplicant.networkPath) |
| { |
| g_object_unref(mWpaSupplicant.networkPath); |
| mWpaSupplicant.networkPath = nullptr; |
| } |
| |
| ret = CHIP_ERROR_INTERNAL; |
| } |
| |
| if (err != nullptr) |
| g_error_free(err); |
| |
| return ret; |
| } |
| |
| void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState) |
| { |
| if (mWiFiAPState != newState) |
| { |
| ChipLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState)); |
| mWiFiAPState = newState; |
| } |
| } |
| |
| void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState) |
| { |
| sInstance.DriveAPState(); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, const char * key) |
| { |
| CHIP_ERROR ret = CHIP_NO_ERROR; |
| GError * err = nullptr; |
| GVariant * args = nullptr; |
| GVariantBuilder builder; |
| gboolean result; |
| |
| // Clean up current network if exists |
| if (mWpaSupplicant.networkPath) |
| { |
| GError * error = nullptr; |
| |
| result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath, |
| nullptr, &error); |
| |
| if (result) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath); |
| g_free(mWpaSupplicant.networkPath); |
| mWpaSupplicant.networkPath = nullptr; |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s", |
| error ? error->message : "unknown error"); |
| ret = CHIP_ERROR_INTERNAL; |
| } |
| |
| if (error != nullptr) |
| g_error_free(error); |
| |
| SuccessOrExit(ret); |
| } |
| |
| g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); |
| g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid)); |
| g_variant_builder_add(&builder, "{sv}", "psk", g_variant_new_string(key)); |
| g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("WPA-PSK")); |
| args = g_variant_builder_end(&builder); |
| |
| result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args, &mWpaSupplicant.networkPath, |
| nullptr, &err); |
| |
| if (result) |
| { |
| GError * error = nullptr; |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath); |
| |
| result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath, |
| nullptr, &error); |
| if (result) |
| { |
| GError * gerror = nullptr; |
| |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to network: SSID: %s", ssid); |
| |
| result = wpa_fi_w1_wpa_supplicant1_interface_call_save_config_sync(mWpaSupplicant.iface, nullptr, &gerror); |
| |
| if (result) |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: save config succeeded!"); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to save config: %s", |
| gerror ? gerror->message : "unknown error"); |
| } |
| |
| if (gerror != nullptr) |
| g_error_free(gerror); |
| |
| // Iterate on the network interface to see if we already have beed assigned addresses. |
| // The temporary hack for getting IP address change on linux for network provisioning in the rendezvous session. |
| // This should be removed or find a better place once we depercate the rendezvous session. |
| for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next()) |
| { |
| char ifName[chip::Inet::InterfaceId::kMaxIfNameLength]; |
| if (it.IsUp() && CHIP_NO_ERROR == it.GetInterfaceName(ifName, sizeof(ifName)) && |
| strncmp(ifName, sWiFiIfName, sizeof(ifName)) == 0) |
| { |
| chip::Inet::IPAddress addr = it.GetAddress(); |
| if (addr.IsIPv4()) |
| { |
| ChipDeviceEvent event; |
| event.Type = DeviceEventType::kInternetConnectivityChange; |
| event.InternetConnectivityChange.IPv4 = kConnectivity_Established; |
| event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; |
| addr.ToString(event.InternetConnectivityChange.address); |
| |
| ChipLogDetail(DeviceLayer, "Got IP address on interface: %s IP: %s", ifName, |
| event.InternetConnectivityChange.address); |
| |
| PlatformMgr().PostEventOrDie(&event); |
| } |
| } |
| } |
| |
| // Run dhclient for IP on WiFi. |
| // TODO: The wifi can be managed by networkmanager on linux so we don't have to care about this. |
| char cmdBuffer[128]; |
| sprintf(cmdBuffer, CHIP_DEVICE_CONFIG_LINUX_DHCPC_CMD, sWiFiIfName); |
| int dhclientSystemRet = system(cmdBuffer); |
| if (dhclientSystemRet != 0) |
| { |
| ChipLogError(DeviceLayer, "Failed to run dhclient, system() returns %d", dhclientSystemRet); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "dhclient is running on the %s interface.", sWiFiIfName); |
| } |
| |
| // Return success as long as the device is connected to the network |
| ret = CHIP_NO_ERROR; |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to connect to network: SSID: %s: %s", ssid, |
| error ? error->message : "unknown error"); |
| |
| ret = CHIP_ERROR_INTERNAL; |
| } |
| |
| if (error != nullptr) |
| g_error_free(error); |
| } |
| else |
| { |
| ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error"); |
| |
| if (mWpaSupplicant.networkPath) |
| { |
| g_object_unref(mWpaSupplicant.networkPath); |
| mWpaSupplicant.networkPath = nullptr; |
| } |
| |
| ret = CHIP_ERROR_INTERNAL; |
| } |
| |
| exit: |
| if (err != nullptr) |
| g_error_free(err); |
| |
| return ret; |
| } |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA |
| |
| void ConnectivityManagerImpl::_ReleaseNetworkInterfaces(NetworkInterface * netifp) |
| { |
| while (netifp) |
| { |
| NetworkInterface * del = netifp; |
| netifp = netifp->Next; |
| delete del; |
| } |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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"); |
| } |
| else |
| { |
| NetworkInterface * head = nullptr; |
| |
| /* Walk through linked list, maintaining head pointer so we |
| can free list later */ |
| for (struct ifaddrs * ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) |
| { |
| if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_PACKET) |
| { |
| NetworkInterface * ifp = new NetworkInterface(); |
| |
| strncpy(ifp->Name, ifa->ifa_name, Inet::InterfaceIterator::kMaxIfNameLength); |
| ifp->Name[Inet::InterfaceIterator::kMaxIfNameLength - 1] = '\0'; |
| |
| ifp->name = CharSpan(ifp->Name, strlen(ifp->Name)); |
| ifp->fabricConnected = ifa->ifa_flags & IFF_RUNNING; |
| ifp->type = ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name); |
| ifp->offPremiseServicesReachableIPv4 = false; |
| ifp->offPremiseServicesReachableIPv6 = false; |
| |
| 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; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_GetEthPHYRate(uint8_t & pHYRate) |
| { |
| if (mEthIfName[0] == '\0') |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| return ConnectivityUtils::GetEthPHYRate(mEthIfName, pHYRate); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_GetEthFullDuplex(bool & fullDuplex) |
| { |
| if (mEthIfName[0] == '\0') |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| return ConnectivityUtils::GetEthFullDuplex(mEthIfName, fullDuplex); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_GetEthTimeSinceReset(uint64_t & timeSinceReset) |
| { |
| return PlatformMgr().GetUpTime(timeSinceReset); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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 ConnectivityManagerImpl::_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 ConnectivityManagerImpl::_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 ConnectivityManagerImpl::_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 ConnectivityManagerImpl::_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 ConnectivityManagerImpl::_ResetEthNetworkDiagnosticsCounts() |
| { |
| return ResetEthernetStatsCount(); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::ResetEthernetStatsCount() |
| { |
| CHIP_ERROR err = CHIP_ERROR_READ_FAILED; |
| struct ifaddrs * ifaddr = nullptr; |
| |
| if (getifaddrs(&ifaddr) == -1) |
| { |
| ChipLogError(DeviceLayer, "Failed to get network interfaces"); |
| } |
| else |
| { |
| struct ifaddrs * ifa = nullptr; |
| |
| /* Walk through linked list, maintaining head pointer so we |
| can free list later */ |
| for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) |
| { |
| if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == InterfaceType::EMBER_ZCL_INTERFACE_TYPE_ETHERNET) |
| { |
| ChipLogProgress(DeviceLayer, "Found the primary Ethernet interface:%s", 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 ConnectivityManagerImpl::_GetWiFiChannelNumber(uint16_t & channelNumber) |
| { |
| if (sWiFiIfName[0] == '\0') |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| return ConnectivityUtils::GetWiFiChannelNumber(sWiFiIfName, channelNumber); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_GetWiFiRssi(int8_t & rssi) |
| { |
| if (sWiFiIfName[0] == '\0') |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| return ConnectivityUtils::GetWiFiRssi(sWiFiIfName, rssi); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_GetWiFiBeaconLostCount(uint32_t & beaconLostCount) |
| { |
| uint32_t count; |
| |
| if (sWiFiIfName[0] == '\0') |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| ReturnErrorOnFailure(ConnectivityUtils::GetWiFiBeaconLostCount(sWiFiIfName, count)); |
| VerifyOrReturnError(count >= mBeaconLostCount, CHIP_ERROR_INVALID_INTEGER_VALUE); |
| beaconLostCount = count - mBeaconLostCount; |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_GetWiFiCurrentMaxRate(uint64_t & currentMaxRate) |
| { |
| if (sWiFiIfName[0] == '\0') |
| { |
| return CHIP_ERROR_READ_FAILED; |
| } |
| |
| return ConnectivityUtils::GetWiFiCurrentMaxRate(sWiFiIfName, currentMaxRate); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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<uint32_t>(count); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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<uint32_t>(count); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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<uint32_t>(count); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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<uint32_t>(count); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::_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 ConnectivityManagerImpl::_ResetWiFiNetworkDiagnosticsCounts() |
| { |
| return ResetWiFiStatsCount(); |
| } |
| |
| CHIP_ERROR ConnectivityManagerImpl::ResetWiFiStatsCount() |
| { |
| 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"); |
| } |
| else |
| { |
| struct ifaddrs * ifa = nullptr; |
| |
| /* Walk through linked list, maintaining head pointer so we |
| can free list later */ |
| for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) |
| { |
| if (ConnectivityUtils::GetInterfaceConnectionType(ifa->ifa_name) == InterfaceType::EMBER_ZCL_INTERFACE_TYPE_WI_FI) |
| { |
| ChipLogProgress(DeviceLayer, "Found the primary WiFi interface:%s", 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 |
| |
| } // namespace DeviceLayer |
| } // namespace chip |