From 72c2cd73961fecd4940ae8fbb62a878f132836d7 Mon Sep 17 00:00:00 2001 From: Gururaaja E S R Date: Wed, 27 Mar 2024 21:09:48 +0000 Subject: [PATCH] Adding NetworkManager plugin --- NetworkManager/CMakeLists.txt | 25 + NetworkManager/cmake | 1 + NetworkManager/interface/CMakeLists.txt | 48 + NetworkManager/interface/INetworkManager.h | 296 ++++ NetworkManager/interface/Module.cpp | 3 + NetworkManager/interface/Module.h | 8 + NetworkManager/service/CMakeLists.txt | 110 ++ NetworkManager/service/Module.cpp | 21 + NetworkManager/service/Module.h | 29 + NetworkManager/service/Network.conf.in | 25 + NetworkManager/service/Network.config | 27 + .../service/NetworkConnectivity.cpp | 633 +++++++ NetworkManager/service/NetworkConnectivity.h | 148 ++ NetworkManager/service/NetworkManager.conf.in | 26 + NetworkManager/service/NetworkManager.config | 27 + NetworkManager/service/NetworkManager.cpp | 169 ++ NetworkManager/service/NetworkManager.h | 424 +++++ NetworkManager/service/NetworkManager.json | 1510 +++++++++++++++++ .../service/NetworkManagerGnomeProxy.cpp | 853 ++++++++++ .../service/NetworkManagerGnomeWIFI.cpp | 727 ++++++++ .../service/NetworkManagerGnomeWIFI.h | 82 + .../service/NetworkManagerImplementation.cpp | 533 ++++++ .../service/NetworkManagerImplementation.h | 242 +++ .../service/NetworkManagerJsonRpc.cpp | 954 +++++++++++ .../service/NetworkManagerLegacy.cpp | 567 +++++++ .../service/NetworkManagerLogger.cpp | 106 ++ NetworkManager/service/NetworkManagerLogger.h | 68 + .../service/NetworkManagerPlugin.json | 15 + .../service/NetworkManagerRDKProxy.cpp | 1194 +++++++++++++ NetworkManager/service/StunClient.cpp | 792 +++++++++ NetworkManager/service/StunClient.h | 191 +++ NetworkManager/service/WiFiManager.conf.in | 25 + NetworkManager/service/WiFiManager.config | 28 + .../service/WifiSignalStrengthMonitor.cpp | 144 ++ .../service/WifiSignalStrengthMonitor.h | 50 + 35 files changed, 10101 insertions(+) create mode 100644 NetworkManager/CMakeLists.txt create mode 120000 NetworkManager/cmake create mode 100644 NetworkManager/interface/CMakeLists.txt create mode 100644 NetworkManager/interface/INetworkManager.h create mode 100644 NetworkManager/interface/Module.cpp create mode 100644 NetworkManager/interface/Module.h create mode 100644 NetworkManager/service/CMakeLists.txt create mode 100644 NetworkManager/service/Module.cpp create mode 100644 NetworkManager/service/Module.h create mode 100644 NetworkManager/service/Network.conf.in create mode 100644 NetworkManager/service/Network.config create mode 100644 NetworkManager/service/NetworkConnectivity.cpp create mode 100644 NetworkManager/service/NetworkConnectivity.h create mode 100644 NetworkManager/service/NetworkManager.conf.in create mode 100644 NetworkManager/service/NetworkManager.config create mode 100644 NetworkManager/service/NetworkManager.cpp create mode 100644 NetworkManager/service/NetworkManager.h create mode 100644 NetworkManager/service/NetworkManager.json create mode 100755 NetworkManager/service/NetworkManagerGnomeProxy.cpp create mode 100644 NetworkManager/service/NetworkManagerGnomeWIFI.cpp create mode 100644 NetworkManager/service/NetworkManagerGnomeWIFI.h create mode 100644 NetworkManager/service/NetworkManagerImplementation.cpp create mode 100644 NetworkManager/service/NetworkManagerImplementation.h create mode 100644 NetworkManager/service/NetworkManagerJsonRpc.cpp create mode 100644 NetworkManager/service/NetworkManagerLegacy.cpp create mode 100644 NetworkManager/service/NetworkManagerLogger.cpp create mode 100644 NetworkManager/service/NetworkManagerLogger.h create mode 100644 NetworkManager/service/NetworkManagerPlugin.json create mode 100644 NetworkManager/service/NetworkManagerRDKProxy.cpp create mode 100644 NetworkManager/service/StunClient.cpp create mode 100644 NetworkManager/service/StunClient.h create mode 100644 NetworkManager/service/WiFiManager.conf.in create mode 100644 NetworkManager/service/WiFiManager.config create mode 100644 NetworkManager/service/WifiSignalStrengthMonitor.cpp create mode 100644 NetworkManager/service/WifiSignalStrengthMonitor.h diff --git a/NetworkManager/CMakeLists.txt b/NetworkManager/CMakeLists.txt new file mode 100644 index 0000000000..c78d8f881b --- /dev/null +++ b/NetworkManager/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.3) + +project(NetworkManager) +find_package(WPEFramework) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +set(VERSION_MAJOR 1) +set(VERSION_MINOR 0) +set(VERSION_PATCH 0) + +add_compile_definitions(NETWORKMANAGER_MAJOR_VERSION=${VERSION_MAJOR}) +add_compile_definitions(NETWORKMANAGER_MINOR_VERSION=${VERSION_MINOR}) +add_compile_definitions(NETWORKMANAGER_PATCH_VERSION=${VERSION_PATCH}) + +set(PROJECT_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + + +include(CmakeHelperFunctions) + +string(TOLOWER ${NAMESPACE} STORAGE_DIRECTORY) +get_directory_property(SEVICES_DEFINES COMPILE_DEFINITIONS) + +add_subdirectory(interface) +add_subdirectory(service) + diff --git a/NetworkManager/cmake b/NetworkManager/cmake new file mode 120000 index 0000000000..8e8a460f74 --- /dev/null +++ b/NetworkManager/cmake @@ -0,0 +1 @@ +../cmake/ \ No newline at end of file diff --git a/NetworkManager/interface/CMakeLists.txt b/NetworkManager/interface/CMakeLists.txt new file mode 100644 index 0000000000..78e85eb410 --- /dev/null +++ b/NetworkManager/interface/CMakeLists.txt @@ -0,0 +1,48 @@ +project(NetworkManagerInterface) +find_package(WPEFramework REQUIRED) +find_package(${NAMESPACE}Core REQUIRED) +find_package(CompileSettingsDebug CONFIG REQUIRED) +find_package(ProxyStubGenerator REQUIRED) + +set(ProxyStubGenerator_DIR ${CMAKE_SYSROOT}${CMAKE_INSTALL_PREFIX}/tools/cmake ${ProxyStubGenerator_DIR}) + +if(NOT GENERATOR_SEARCH_PATH) + set(GENERATOR_SEARCH_PATH ${CMAKE_SYSROOT}${CMAKE_INSTALL_PREFIX}/include/${NAMESPACE}) +endif() + +ProxyStubGenerator(INPUT "${CMAKE_CURRENT_SOURCE_DIR}" OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/generated" INCLUDE_PATH ${GENERATOR_SEARCH_PATH}) + +file(GLOB INTERFACES_HEADERS I*.h) +list(APPEND INTERFACES_HEADERS Module.h) + +file(GLOB PROXY_STUB_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/generated/ProxyStubs*.cpp") + +set(TARGET ${NAMESPACE}NetworkManagerInterface) +string(TOLOWER ${NAMESPACE} NAMESPACE_LIB) + +add_library(${TARGET} SHARED ${PROXY_STUB_SOURCES} Module.cpp) + +target_include_directories( ${TARGET} PUBLIC $) + +target_link_libraries(${TARGET} PRIVATE ${NAMESPACE}Core::${NAMESPACE}Core) +target_link_libraries(${TARGET} PRIVATE CompileSettingsDebug::CompileSettingsDebug) + +set_target_properties(${TargetMarshalling} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES + FRAMEWORK FALSE + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) + +install( + TARGETS ${TARGET} EXPORT ${TARGET}Targets # for downstream dependencies + ARCHIVE DESTINATION lib/${NAMESPACE_LIB}/proxystubs COMPONENT libs # static lib + LIBRARY DESTINATION lib/${NAMESPACE_LIB}/proxystubs COMPONENT libs # shared lib + RUNTIME DESTINATION bin COMPONENT libs # binaries + FRAMEWORK DESTINATION bin/${NAMESPACE_LIB}/proxystubs COMPONENT libs # for mac + PUBLIC_HEADER DESTINATION include/${NAMESPACE}/proxystubs COMPONENT devel # headers for mac (note the different component -> different package) + INCLUDES DESTINATION include/${NAMESPACE}/proxystubs # headers +) + +InstallCMakeConfig(TARGETS ${TARGET}) diff --git a/NetworkManager/interface/INetworkManager.h b/NetworkManager/interface/INetworkManager.h new file mode 100644 index 0000000000..eba176c327 --- /dev/null +++ b/NetworkManager/interface/INetworkManager.h @@ -0,0 +1,296 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2023 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ + +#pragma once +#include "Module.h" + +// @stubgen:include + +namespace WPEFramework +{ + namespace Exchange + { + enum myNetwork_ids { + ID_NETWORKMANAGER = 0x800004E0, + ID_NETWORKMANAGER_NOTIFICATION = ID_NETWORKMANAGER + 1, + ID_NETWORKMANAGER_INTERFACE_DETAILS_ITERATOR = ID_NETWORKMANAGER + 2, + ID_NETWORKMANAGER_WIFI_SECURITY_MODE_ITERATOR = ID_NETWORKMANAGER + 3 + }; + + /* @json */ + struct EXTERNAL INetworkManager: virtual public Core::IUnknown + { + // All interfaces require a unique ID, defined in Ids.h + enum { ID = ID_NETWORKMANAGER }; + + // Define the RPC methods + enum InterfaceType : uint8_t + { + INTERFACE_TYPE_ETHERNET, + INTERFACE_TYPE_WIFI, + INTERFACE_TYPE_P2P, + }; + + struct EXTERNAL InterfaceDetails { + string m_type; + string m_name; + string m_mac; + bool m_isEnabled; + bool m_isConnected; + }; + + enum IPAddressType : uint8_t + { + IP_ADDRESS_V4, + IP_ADDRESS_V6, + IP_ADDRESS_BOTH + }; + + struct EXTERNAL IPAddressInfo { + string m_ipAddrType; + bool m_autoConfig; + string m_dhcpServer; + string m_v6LinkLocal; + string m_ipAddress; + uint32_t m_prefix; + string m_gateway; + string m_primaryDns; + string m_secondaryDns; + }; + + // Define the RPC methods + enum InternetStatus : uint8_t + { + INTERNET_NOT_AVAILABLE, + INTERNET_LIMITED, + INTERNET_CAPTIVE_PORTAL, + INTERNET_FULLY_CONNECTED, + INTERNET_UNKNOWN, + }; + + enum WiFiFrequency : uint8_t + { + WIFI_FREQUENCY_WHATEVER, + WIFI_FREQUENCY_2_4_GHZ, + WIFI_FREQUENCY_5_GHZ, + WIFI_FREQUENCY_6_GHZ + }; + + enum WiFiWPS : uint8_t + { + WIFI_WPS_PBC, + WIFI_WPS_PIN, + WIFI_WPS_SERIALIZED_PIN + }; + + enum WIFISecurityMode : uint8_t + { + WIFI_SECURITY_NONE, + WIFI_SECURITY_WEP_64, + WIFI_SECURITY_WEP_128, + WIFI_SECURITY_WPA_PSK_TKIP, + WIFI_SECURITY_WPA_PSK_AES, + WIFI_SECURITY_WPA2_PSK_TKIP, + WIFI_SECURITY_WPA2_PSK_AES, + WIFI_SECURITY_WPA_ENTERPRISE_TKIP, + WIFI_SECURITY_WPA_ENTERPRISE_AES, + WIFI_SECURITY_WPA2_ENTERPRISE_TKIP, + WIFI_SECURITY_WPA2_ENTERPRISE_AES, + WIFI_SECURITY_WPA_WPA2_PSK, + WIFI_SECURITY_WPA_WPA2_ENTERPRISE, + WIFI_SECURITY_WPA3_PSK_AES, + WIFI_SECURITY_WPA3_SAE + }; + + struct EXTERNAL WiFiScanResults { + string m_ssid; + WIFISecurityMode m_securityMode; + string m_signalStrength; + WiFiFrequency m_frequency; + }; + + struct EXTERNAL WiFiConnectTo { + string m_ssid; + string m_passphrase; + WIFISecurityMode m_securityMode; + }; + + struct EXTERNAL WiFiSSIDInfo { + string m_ssid; + string m_bssid; + WIFISecurityMode m_securityMode; + string m_signalStrength; + WiFiFrequency m_frequency; + string m_rate; + string m_noise; + }; + + struct EXTERNAL WIFISecurityModeInfo { + WIFISecurityMode m_securityMode; + string m_securityModeText; + }; + + enum WiFiSignalQuality : uint8_t + { + WIFI_SIGNAL_DISCONNECTED, + WIFI_SIGNAL_WEAK, + WIFI_SIGNAL_FAIR, + WIFI_SIGNAL_GOOD, + WIFI_SIGNAL_EXCELLENT + }; + + enum NMLogging : uint8_t + { + LOG_LEVEL_FATAL, + LOG_LEVEL_ERROR, + LOG_LEVEL_WARNING, + LOG_LEVEL_INFO, + LOG_LEVEL_VERBOSE, + LOG_LEVEL_TRACE + }; + + // The state of the interface + enum InterfaceState : uint8_t + { + INTERFACE_ADDED, + INTERFACE_LINK_UP, + INTERFACE_LINK_DOWN, + INTERFACE_ACQUIRING_IP, + INTERFACE_REMOVED, + INTERFACE_DISABLED + }; + + enum WiFiState : uint8_t + { + WIFI_STATE_UNINSTALLED, + WIFI_STATE_DISABLED, + WIFI_STATE_DISCONNECTED, + WIFI_STATE_PAIRING, + WIFI_STATE_CONNECTING, + WIFI_STATE_CONNECTED, + WIFI_STATE_SSID_NOT_FOUND, + WIFI_STATE_SSID_CHANGED, + WIFI_STATE_CONNECTION_LOST, + WIFI_STATE_CONNECTION_FAILED, + WIFI_STATE_CONNECTION_INTERRUPTED, + WIFI_STATE_INVALID_CREDENTIALS, + WIFI_STATE_AUTHENTICATION_FAILED, + WIFI_STATE_ERROR + }; + + using IInterfaceDetailsIterator = RPC::IIteratorType; + using ISecurityModeIterator = RPC::IIteratorType; + using IStringIterator = RPC::IIteratorType; + + /* @brief Get all the Available Interfaces */ + virtual uint32_t GetAvailableInterfaces (IInterfaceDetailsIterator*& interfaces/* @out */) = 0; + + /* @brief Get the Primary Interface used for external world communication */ + virtual uint32_t GetPrimaryInterface (string& interface /* @out */) = 0; + /* @brief Set the Primary Interface used for external world communication */ + virtual uint32_t SetPrimaryInterface (const string& interface/* @in */) = 0; + + /* @brief Enable the active Interface used for external world communication */ + virtual uint32_t EnableInterface (const string& interface/* @in */) = 0; + /* @brief Disable the Interface passed */ + virtual uint32_t DisableInterface (const string& interface/* @in */) = 0; + + /* @brief Get IP Address Of the Interface */ + virtual uint32_t GetIPSettings(const string& interface /* @in */, const string &ipversion /* @in */, IPAddressInfo& result /* @out */) = 0; + /* @brief Set IP Address Of the Interface */ + virtual uint32_t SetIPSettings(const string& interface /* @in */, const string &ipversion /* @in */, const IPAddressInfo& address /* @in */) = 0; + + /* @brief Get STUN Endpoint to be used for identifying Public IP */ + virtual uint32_t GetStunEndpoint (string &endPoint /* @out */, uint32_t &port /* @out */, uint32_t &bindTimeout /* @out */, uint32_t &cacheTimeout /* @out */) const = 0; + /* @brief Set STUN Endpoint to be used to identify Public IP */ + virtual uint32_t SetStunEndpoint (string const endPoint /* @in */, const uint32_t port /* @in */, const uint32_t bindTimeout /* @in */, const uint32_t cacheTimeout /* @in */) = 0; + + /* @brief Get ConnectivityTest Endpoints */ + virtual uint32_t GetConnectivityTestEndpoints(IStringIterator*& endPoints/* @out */) const = 0; + /* @brief Set ConnectivityTest Endpoints */ + virtual uint32_t SetConnectivityTestEndpoints(IStringIterator* const endPoints /* @in */) = 0; + + /* @brief Get Internet Connectivty Status */ + virtual uint32_t IsConnectedToInternet(const string &ipversion /* @in */, InternetStatus &result /* @out */) = 0; + /* @brief Get Authentication URL if the device is behind Captive Portal */ + virtual uint32_t GetCaptivePortalURI(string &endPoints/* @out */) const = 0; + + /* @brief Start The Internet Connectivity Monitoring */ + virtual uint32_t StartConnectivityMonitoring(const uint32_t interval /* @in */) = 0; + /* @brief Stop The Internet Connectivity Monitoring */ + virtual uint32_t StopConnectivityMonitoring(void) const = 0; + + /* @brief Get the Public IP used for external world communication */ + virtual uint32_t GetPublicIP (const string &ipversion /* @in */, string& ipAddress /* @out */) = 0; + + /* @brief Request for ping and get the response in as event. The GUID used in the request will be returned in the event. */ + virtual uint32_t Ping (const string ipversion /* @in */, const string endpoint /* @in */, const uint32_t noOfRequest /* @in */, const uint16_t timeOutInSeconds /* @in */, const string guid /* @in */, string& response /* @out */) = 0; + + /* @brief Request for trace get the response in as event. The GUID used in the request will be returned in the event. */ + virtual uint32_t Trace (const string ipversion /* @in */, const string endpoint /* @in */, const uint32_t noOfRequest /* @in */, const string guid /* @in */, string& response /* @out */) = 0; + + + // WiFi Specific Methods + /* @brief Initiate a WIFI Scan; This is Async method and returns the scan results as Event */ + virtual uint32_t StartWiFiScan(const WiFiFrequency frequency /* @in */) = 0; + virtual uint32_t StopWiFiScan(void) = 0; + + virtual uint32_t GetKnownSSIDs(IStringIterator*& ssids /* @out */) = 0; + virtual uint32_t AddToKnownSSIDs(const WiFiConnectTo& ssid /* @in */) = 0; + virtual uint32_t RemoveKnownSSID(const string& ssid /* @in */) = 0; + + virtual uint32_t WiFiConnect(const WiFiConnectTo& ssid /* @in */) = 0; + virtual uint32_t WiFiDisconnect(void) = 0; + virtual uint32_t GetConnectedSSID(WiFiSSIDInfo& ssidInfo /* @out */) = 0; + + virtual uint32_t StartWPS(const WiFiWPS& method /* @in */, const string& wps_pin /* @in */) = 0; + virtual uint32_t StopWPS(void) = 0; + virtual uint32_t GetWifiState(WiFiState &state /* @out */) = 0; + virtual uint32_t GetWiFiSignalStrength(string& ssid /* @out */, string& signalStrength /* @out */, WiFiSignalQuality& quality /* @out */) = 0; + virtual uint32_t GetSupportedSecurityModes(ISecurityModeIterator*& securityModes /* @out */) const = 0; + + /* @brief Set the network manager plugin log level */ + virtual uint32_t SetLogLevel(const NMLogging& logLevel /* @in */) = 0; + + /* @brief configure network manager plugin */ + virtual uint32_t Configure(const string& configLine /* @in */, NMLogging& logLevel /* @out */) = 0; + + /* @event */ + struct EXTERNAL INotification : virtual public Core::IUnknown + { + enum { ID = ID_NETWORKMANAGER_NOTIFICATION }; + + // Network Notifications that other processes can subscribe to + virtual void onInterfaceStateChange(const InterfaceState event /* @in */, const string interface /* @in */) = 0; + virtual void onActiveInterfaceChange(const string prevActiveInterface /* @in */, const string currentActiveinterface /* @in */) = 0; + virtual void onIPAddressChange(const string interface /* @in */, const bool isAcquired /* @in */, const bool isIPv6 /* @in */, const string ipAddress /* @in */) = 0; + virtual void onInternetStatusChange(const InternetStatus oldState /* @in */, const InternetStatus newstate /* @in */) = 0; + + // WiFi Notifications that other processes can subscribe to + virtual void onAvailableSSIDs(const string jsonOfWiFiScanResults /* @in */) = 0; + virtual void onWiFiStateChange(const WiFiState state /* @in */) = 0; + virtual void onWiFiSignalStrengthChange(const string ssid /* @in */, const string signalLevel /* @in */, const WiFiSignalQuality signalQuality /* @in */) = 0; + }; + + // Allow other processes to register/unregister from our notifications + virtual uint32_t Register(INetworkManager::INotification* notification) = 0; + virtual uint32_t Unregister(INetworkManager::INotification* notification) = 0; + }; + } +} diff --git a/NetworkManager/interface/Module.cpp b/NetworkManager/interface/Module.cpp new file mode 100644 index 0000000000..2d85ed902b --- /dev/null +++ b/NetworkManager/interface/Module.cpp @@ -0,0 +1,3 @@ +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/NetworkManager/interface/Module.h b/NetworkManager/interface/Module.h new file mode 100644 index 0000000000..aa41a21789 --- /dev/null +++ b/NetworkManager/interface/Module.h @@ -0,0 +1,8 @@ +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME INetworkManager +#endif + +#include +#include diff --git a/NetworkManager/service/CMakeLists.txt b/NetworkManager/service/CMakeLists.txt new file mode 100644 index 0000000000..f7a37d1fdb --- /dev/null +++ b/NetworkManager/service/CMakeLists.txt @@ -0,0 +1,110 @@ +# If not stated otherwise in this file or this component's LICENSE +# file the following copyright and licenses apply: +# +# Copyright 2022 RDK Management +# +# 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. + +set(PLUGIN_NAME NetworkManager) +set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) +set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) + +find_package(${NAMESPACE}Core REQUIRED) +find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) +find_package(CURL) +if(ENABLE_GNOME_NETWORKMANAGER) +pkg_check_modules(GLIB REQUIRED glib-2.0) +pkg_check_modules(LIBNM REQUIRED libnm) +else() +find_package(IARMBus REQUIRED) +endif () + +message("Setup ${PROJECT_NAME} v${PROJECT_VERSION}") + +set(PLUGIN_NETWORKMANAGER_LOGLEVEL "5" CACHE STRING "To configure default loglevel NetworkManager plugin") + +# Build the main plugin that runs inside the WPEFramework daemon +add_library(${MODULE_NAME} SHARED + NetworkManager.cpp + NetworkManagerJsonRpc.cpp + NetworkManagerLogger.cpp + Module.cpp +) + +if(ENABLE_LEGACY_NSM_SUPPORT) +target_sources(${MODULE_NAME} PRIVATE NetworkManagerLegacy.cpp) +endif () + +if(ENABLE_LEGACY_NSM_SUPPORT) +add_definitions(-DENABLE_LEGACY_NSM_SUPPORT) +endif () + +target_link_libraries(${MODULE_NAME} PRIVATE + ${NAMESPACE}Core::${NAMESPACE}Core + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) + +set_target_properties(${MODULE_NAME} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + +include_directories(${PROJECT_SOURCE_DIR}/interface) +include_directories(${PROJECT_SOURCE_DIR}/service) +include_directories(${PROJECT_SOURCE_DIR}/../helpers) + +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) + + +# Build the implementation that runs out-of-process behind a COM-RPC interface +add_library(${PLUGIN_IMPLEMENTATION} SHARED + NetworkManagerImplementation.cpp + NetworkConnectivity.cpp + NetworkManagerLogger.cpp + StunClient.cpp + WifiSignalStrengthMonitor.cpp + Module.cpp + ${PUBLIC_HEADERS} +) + +if(ENABLE_GNOME_NETWORKMANAGER) + target_sources(${PLUGIN_IMPLEMENTATION} PRIVATE NetworkManagerGnomeProxy.cpp NetworkManagerGnomeWIFI.cpp) + target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${GLIB_INCLUDE_DIRS} ${LIBNM_INCLUDE_DIRS}) + target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${LIBNM_LIBRARIES}) +else() + target_sources(${PLUGIN_IMPLEMENTATION} PRIVATE NetworkManagerRDKProxy.cpp) + target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS}) + target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_LIBRARIES}) +endif() + +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) + +set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES + FRAMEWORK FALSE) + +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${CURL_LIBRARIES}) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${CURL_INCLUDE_DIRS}) + +install(TARGETS ${PLUGIN_IMPLEMENTATION} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/${STORAGE_DIRECTORY}/plugins) + +write_config() + +if(ENABLE_LEGACY_NSM_SUPPORT) +add_definitions(-DENABLE_LEGACY_NSM_SUPPORT) +write_config(Network) +write_config(WiFiManager) +endif () diff --git a/NetworkManager/service/Module.cpp b/NetworkManager/service/Module.cpp new file mode 100644 index 0000000000..a574f23dbe --- /dev/null +++ b/NetworkManager/service/Module.cpp @@ -0,0 +1,21 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* 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 "Module.h" +MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/NetworkManager/service/Module.h b/NetworkManager/service/Module.h new file mode 100644 index 0000000000..b6552bb9dd --- /dev/null +++ b/NetworkManager/service/Module.h @@ -0,0 +1,29 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ + +#pragma once + +// The module name is used for trace control - every plugin should have a unique module name +// to allow for runtime control of plugin log levels +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_NetworkManager +#endif + +#include +#include diff --git a/NetworkManager/service/Network.conf.in b/NetworkManager/service/Network.conf.in new file mode 100644 index 0000000000..74bb46f4b3 --- /dev/null +++ b/NetworkManager/service/Network.conf.in @@ -0,0 +1,25 @@ +autostart = "true" +callsign= "org.rdk.Network" + +test = JSON() +test.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") +test.add("outofprocess", "true") + +connectivity = JSON() +connectivity.add("endpoint_1", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_1@") +connectivity.add("endpoint_2", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_2@") +connectivity.add("endpoint_3", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_3@") +connectivity.add("endpoint_4", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_4@") +connectivity.add("endpoint_5", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_5@") +connectivity.add("interval", "@PLUGIN_NETWORKMANAGER_CONN_MONITOR_INTERVAL@") + +stun = JSON() +stun.add("endpoint", "@PLUGIN_NETWORKMANAGER_STUN_ENDPOINT@") +stun.add("port", "@PLUGIN_NETWORKMANAGER_STUN_PORT@") +stun.add("interval", "30") + +configuration = JSON() +configuration.add("root", test) +configuration.add("connectivity", connectivity) +configuration.add("stun", stun) +configuration.add("loglevel", "@PLUGIN_NETWORKMANAGER_LOGLEVEL@") diff --git a/NetworkManager/service/Network.config b/NetworkManager/service/Network.config new file mode 100644 index 0000000000..5cb22809f2 --- /dev/null +++ b/NetworkManager/service/Network.config @@ -0,0 +1,27 @@ +set(autostart true) +set(callsign "org.rdk.Network") + +map() + key(root) + map() + kv(outofprocess true) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() + key(connectivity) + map() + kv(endpoint_1 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_1}) + kv(endpoint_2 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_2}) + kv(endpoint_3 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_3}) + kv(endpoint_4 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_4}) + kv(endpoint_5 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_5}) + kv(interval, @PLUGIN_NETWORKMANAGER_CONN_MONITOR_INTERVAL@) + end() + key(stun) + map() + kv(endpoint, ${PLUGIN_NETWORKMANAGER_STUN_ENDPOINT}) + kv(port, PLUGIN_NETWORKMANAGER_STUN_PORT) + kv(interval, 30) + end() + kv(loglevel, 3) +end() +ans(configuration) diff --git a/NetworkManager/service/NetworkConnectivity.cpp b/NetworkManager/service/NetworkConnectivity.cpp new file mode 100644 index 0000000000..e34688dc1c --- /dev/null +++ b/NetworkManager/service/NetworkConnectivity.cpp @@ -0,0 +1,633 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Module.h" +#include "NetworkConnectivity.h" +#include "NetworkManagerImplementation.h" + +namespace WPEFramework { + namespace Plugin { + + extern NetworkManagerImplementation* _instance; + + bool EndpointCache::isEndpointCashFileExist() + { + std::ifstream fileStream(CachefilePath); + return fileStream.is_open(); + } + + void EndpointCache::writeEnpointsToFile(const std::vector& endpoints) + { + std::ofstream outputFile(CachefilePath); + if (outputFile.is_open()) + { + for (const std::string& str : endpoints) + { + outputFile << str << '\n'; + } + outputFile.close(); + NMLOG_INFO("Connectivity endpoints successfully written to a file"); + } + else + { + NMLOG_ERROR("Connectivity endpoints file write error"); + } + } + + std::vector EndpointCache::readEnpointsFromFile() + { + std::vector readStrings; + std::ifstream inputFile(CachefilePath); + if (inputFile.is_open()) + { + std::string line; + while (std::getline(inputFile, line)) + { + readStrings.push_back(line); + } + inputFile.close(); + } + else + { + NMLOG_ERROR("Failed to open connectivity endpoint cache file"); + } + return readStrings; + } + + void Connectivity::loadConnectivityConfig(const std::string& configFilePath) + { + std::ifstream configFile(configFilePath); + if (!configFile.is_open()) + { + NMLOG_ERROR("Unable to open the configuration file: %s", configFilePath.c_str()); + return; + } + + bool ConnectivityConfigFound = false; + + // load connectivity endpoint configuration + std::string line; + while (std::getline(configFile, line)) + { + if (line == "[Connectivity_Config]") + { + ConnectivityConfigFound = true; + continue; + } + + if (ConnectivityConfigFound) + { + size_t equalsPos = line.find('='); + if (equalsPos != std::string::npos) + { + std::string key = line.substr(0, equalsPos); + std::string value = line.substr(equalsPos + 1); + configMap[key] = value; + } + } + } + + configFile.close(); + + /* Parse the connectivity monitor interval and enable values */ + configMonitorConnectivityEnabled = ((configMap["CONNECTIVITY_MONITOR_ENABLE"] == "1")? true:false); + std::string monitorIntervalStr = configMap["CONNECTIVITY_MONITOR_INTERVAL"]; + if (!monitorIntervalStr.empty()) + { + configMonitorInterval = std::stoi(monitorIntervalStr); + } + + m_defaultEndpoints.clear(); + for (int i = 1; i <= 5; ++i) + { + std::string endpointName = "CONNECTIVITY_ENDPOINT_" + std::to_string(i); + auto endpoint = configMap.find(endpointName); + if (endpoint != configMap.end() && endpoint->second.length() > 3) + { + m_defaultEndpoints.push_back(endpoint->second); + } + } + + if(m_defaultEndpoints.empty()) + { + NMLOG_ERROR("Default endpoints are empty !!"); + } + else + { + std::string endpoints_str; + for (const auto& endpoint : m_defaultEndpoints) + endpoints_str.append(endpoint).append(" "); + NMLOG_INFO("default endpoints count %d and endpoints:- %s", static_cast(m_defaultEndpoints.size()), endpoints_str.c_str()); + NMLOG_INFO("default monitor connectivity interval: %d and monitor connectivity auto start : %s", configMonitorInterval, configMonitorConnectivityEnabled?"true":"false"); + } + } + + bool ConnectivityMonitor::isConnectivityMonitorEndpointSet() + { + const std::lock_guard lock(endpointMutex); + if(monitorEndpoints.size() > 0) + { + return true; + } + else if(endpointCache.isEndpointCashFileExist()) + { + monitorEndpoints = endpointCache.readEnpointsFromFile(); + std::string endpoints_str; + for (const auto& endpoint : monitorEndpoints) + endpoints_str.append(endpoint).append(" "); + NMLOG_INFO("updated endpoints count %d and endpoints:- %s", static_cast(monitorEndpoints.size()), endpoints_str.c_str()); + if(monitorEndpoints.size() > 0) + return true; + } + return false; + } + + bool ConnectivityMonitor::isConnectedToInternet(nsm_ipversion ipversion) + { + if (nsm_internetState::FULLY_CONNECTED == getInternetConnectionState(ipversion)) + { + NMLOG_INFO("isConnectedToInternet = true"); + return true; + } + + NMLOG_WARNING("isConnectedToInternet = false"); + return false; + } + + nsm_internetState ConnectivityMonitor::getInternetConnectionState(nsm_ipversion ipversion) + { + + nsm_internetState internetState = nsm_internetState::UNKNOWN; + + // If monitor connectivity is running take the cashe value + if ( isMonitorThreadRunning() && (ipversion == NSM_IPRESOLVE_WHATEVER) && (g_internetState != nsm_internetState::UNKNOWN) ) + { + internetState = g_internetState; + } + else + { + if(isConnectivityMonitorEndpointSet()) + internetState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion); + else + internetState = testConnectivity(getConnectivityDefaultEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, ipversion); + } + + return internetState; + } + + std::string ConnectivityMonitor::getCaptivePortalURI() + { + if (g_internetState == nsm_internetState::CAPTIVE_PORTAL) + { + return getCaptivePortal(); + } + else + { + std::string captivePortal; + if(getInternetConnectionState(NSM_IPRESOLVE_WHATEVER) == nsm_internetState::CAPTIVE_PORTAL) + { + return getCaptivePortal(); + } + else + NMLOG_WARNING("No captive portal found !"); + } + return std::string(""); + } + + void ConnectivityMonitor::setConnectivityMonitorEndpoints(const std::vector &endpoints) + { + const std::lock_guard lock(endpointMutex); + monitorEndpoints.clear(); + for (auto endpoint : endpoints) { + if(!endpoint.empty() && endpoint.size() > 3) + monitorEndpoints.push_back(endpoint.c_str()); + else + NMLOG_INFO("endpoint not vallied = %s", endpoint.c_str()); + } + + // write the endpoints to a file + endpointCache.writeEnpointsToFile(monitorEndpoints); + + std::string endpoints_str; + for (const auto& endpoint : monitorEndpoints) + endpoints_str.append(endpoint).append(" "); + NMLOG_INFO("Connectivity monitor endpoints -: %d :- %s", static_cast(monitorEndpoints.size()), endpoints_str.c_str()); + } + + std::vector ConnectivityMonitor::getConnectivityMonitorEndpoints() + { + const std::lock_guard lock(endpointMutex); + std::vector endpoints; + for (auto endpoint : monitorEndpoints) { + endpoints.push_back(endpoint); + } + return endpoints; + } + + static bool curlVerboseEnabled() { + std::ifstream fileStream("/tmp/network.plugin.debug"); + return fileStream.is_open(); + } + + static long current_time () + { + struct timespec ts; + clock_gettime (CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000); + } + static size_t writeFunction(void* ptr, size_t size, size_t nmemb, std::string* data) { + #ifdef DBG_CURL_GET_RESPONSE + NMLOG_TRACE("%s",(char*)ptr); + #endif + return size * nmemb; + } + + nsm_internetState Connectivity::testConnectivity(const std::vector& endpoints, long timeout_ms, nsm_ipversion ipversion) + { + long deadline = current_time() + timeout_ms, time_now = 0, time_earlier = 0; + if(endpoints.size() < 1) { + NMLOG_ERROR("endpoints size error ! "); + return NO_INTERNET; + } + + CURLM *curl_multi_handle = curl_multi_init(); + if (!curl_multi_handle) + { + NMLOG_ERROR("curl_multi_init returned NULL"); + return NO_INTERNET; + } + + CURLMcode mc; + std::vector curl_easy_handles; + std::vector http_responses; + struct curl_slist *chunk = NULL; + chunk = curl_slist_append(chunk, "Cache-Control: no-cache, no-store"); + chunk = curl_slist_append(chunk, "Connection: close"); + for (const auto& endpoint : endpoints) + { + CURL *curl_easy_handle = curl_easy_init(); + if (!curl_easy_handle) + { + NMLOG_ERROR("endpoint = <%s> curl_easy_init returned NULL", endpoint.c_str()); + continue; + } + curl_easy_setopt(curl_easy_handle, CURLOPT_URL, endpoint.c_str()); + curl_easy_setopt(curl_easy_handle, CURLOPT_PRIVATE, endpoint.c_str()); + /* set our custom set of headers */ + curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPHEADER, chunk); + curl_easy_setopt(curl_easy_handle, CURLOPT_USERAGENT, "RDKCaptiveCheck/1.0"); + /* set CURLOPT_HTTPGET option insted of CURLOPT_CONNECT_ONLY bcause we need to get the captiveportal URI not just connection only */ + /* HTTPGET request added insted of HTTPHEAD request fix for DELIA-61526 */ + curl_easy_setopt(curl_easy_handle, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(curl_easy_handle, CURLOPT_WRITEFUNCTION, writeFunction); + curl_easy_setopt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time()); + if ((ipversion == CURL_IPRESOLVE_V4) || (ipversion == CURL_IPRESOLVE_V6)) + curl_easy_setopt(curl_easy_handle, CURLOPT_IPRESOLVE, ipversion); + if(curlVerboseEnabled()) + curl_easy_setopt(curl_easy_handle, CURLOPT_VERBOSE, 1L); + if (CURLM_OK != (mc = curl_multi_add_handle(curl_multi_handle, curl_easy_handle))) + { + NMLOG_ERROR("endpoint = <%s> curl_multi_add_handle returned %d (%s)", endpoint.c_str(), mc, curl_multi_strerror(mc)); + curl_easy_cleanup(curl_easy_handle); + continue; + } + curl_easy_handles.push_back(curl_easy_handle); + } + int handles, msgs_left; + char *url = nullptr; + #if LIBCURL_VERSION_NUM < 0x074200 + int numfds, repeats = 0; + #endif + char *endpoint; + while (1) + { + if (CURLM_OK != (mc = curl_multi_perform(curl_multi_handle, &handles))) + { + NMLOG_ERROR("curl_multi_perform returned %d (%s)", mc, curl_multi_strerror(mc)); + break; + } + for (CURLMsg *msg; NULL != (msg = curl_multi_info_read(curl_multi_handle, &msgs_left)); ) + { + long response_code = -1; + if (msg->msg != CURLMSG_DONE) + continue; + if (CURLE_OK == msg->data.result) { + curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &endpoint); + if (curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK) { + if(curlVerboseEnabled()) + NMLOG_INFO("endpoint = <%s> response code <%d>",endpoint, static_cast(response_code)); + if (HttpStatus_302_Found == response_code) { + if ( (curl_easy_getinfo(msg->easy_handle, CURLINFO_REDIRECT_URL, &url) == CURLE_OK) && url != nullptr) { + //NMLOG_WARNING("captive portal found !!!"); + setCaptivePortal(url); + } + } + } + } + else + NMLOG_TRACE("endpoint = <%s> error = %d (%s)", endpoint, msg->data.result, curl_easy_strerror(msg->data.result)); + http_responses.push_back(response_code); + } + time_earlier = time_now; + time_now = current_time(); + if (handles == 0 || time_now >= deadline) + break; + #if LIBCURL_VERSION_NUM < 0x074200 + if (CURLM_OK != (mc = curl_multi_wait(curl_multi_handle, NULL, 0, deadline - time_now, &numfds))) + { + NMLOG_ERROR("curl_multi_wait returned %d (%s)", mc, curl_multi_strerror(mc)); + break; + } + if (numfds == 0) + { + repeats++; + if (repeats > 1) + usleep(10*1000); /* sleep 10 ms */ + } + else + repeats = 0; + #else + if (CURLM_OK != (mc = curl_multi_poll(curl_multi_handle, NULL, 0, deadline - time_now, NULL))) + { + NMLOG_ERROR("curl_multi_poll returned %d (%s)", mc, curl_multi_strerror(mc)); + break; + } + #endif + } + if(curlVerboseEnabled()) { + NMLOG_INFO("endpoints count = %d response count %d, handles = %d, deadline = %ld, time_now = %ld, time_earlier = %ld", + static_cast(endpoints.size()), static_cast(http_responses.size()), handles, deadline, time_now, time_earlier); + } + for (const auto& curl_easy_handle : curl_easy_handles) + { + curl_easy_getinfo(curl_easy_handle, CURLINFO_PRIVATE, &endpoint); + //NMLOG_TRACE("endpoint = <%s> terminating attempt", endpoint); + curl_multi_remove_handle(curl_multi_handle, curl_easy_handle); + curl_easy_cleanup(curl_easy_handle); + } + curl_multi_cleanup(curl_multi_handle); + /* free the custom headers */ + curl_slist_free_all(chunk); + return checkInternetStateFromResponseCode(http_responses); + } + + /* + * verifying Most occurred response code is 50 % or more + * Example 1 : + * if we have 5 endpoints so response also 5 ( 204 302 204 204 200 ) . Here count is 204 :- 3, 302 :- 1, 200 :- 1 + * Return Internet State: FULLY_CONNECTED - 60 % + * Example 2 : + * if we have 4 endpoints so response also 4 ( 204 204 200 200 ) . Here count is 204 :- 2, 200 :- 2 + * Return Internet State: FULLY_CONNECTED - 50 % + */ + + nsm_internetState Connectivity::checkInternetStateFromResponseCode(const std::vector& responses) + { + nsm_internetState InternetConnectionState = NO_INTERNET; + nsm_connectivity_httpcode http_response_code = HttpStatus_response_error; + + int max_count = 0; + for (int element : responses) + { + int element_count = count(responses.begin(), responses.end(), element); + if (element_count > max_count) + { + http_response_code = static_cast(element); + max_count = element_count; + } + } + + /* Calculate the percentage of the most frequent code occurrences */ + float percentage = (static_cast(max_count) / responses.size()); + + /* 50 % connectivity check */ + if (percentage >= 0.5) + { + switch (http_response_code) + { + case HttpStatus_204_No_Content: + InternetConnectionState = FULLY_CONNECTED; + NMLOG_INFO("Internet State: FULLY_CONNECTED - %.1f%%", (percentage*100)); + break; + case HttpStatus_200_OK: + InternetConnectionState = LIMITED_INTERNET; + NMLOG_INFO("Internet State: LIMITED_INTERNET - %.1f%%", (percentage*100)); + break; + case HttpStatus_511_Authentication_Required: + case HttpStatus_302_Found: + InternetConnectionState = CAPTIVE_PORTAL; + NMLOG_INFO("Internet State: CAPTIVE_PORTAL -%.1f%%", (percentage*100)); + break; + default: + InternetConnectionState = NO_INTERNET; + NMLOG_INFO("Internet State: NO_INTERNET Response code: <%d> %.1f%%", static_cast(http_response_code), (percentage*100)); + } + } + + return InternetConnectionState; + } + + bool ConnectivityMonitor::doContinuousConnectivityMonitoring(int timeoutInSeconds) + { + if(!isConnectivityMonitorEndpointSet()) + { + NMLOG_INFO("Connectivity monitor endpoints are not set !"); + return false; + } + + timeout.store(timeoutInSeconds >= MONITOR_TIMEOUT_INTERVAL_MIN ? timeoutInSeconds:defaultTimeoutInSec); + + if (isMonitorThreadRunning()) + { + isContinuesMonitoringNeeded = true; + cv_.notify_all(); + NMLOG_INFO("Connectivity monitor Restarted with %d", timeout.load()); + //TODO check still active + } + else + { + if (thread_.joinable()) + { + NMLOG_WARNING("Connectivity Monitor joinable Thread is active"); + stopFlag = true; + cv_.notify_all(); + thread_.join(); + } + + isContinuesMonitoringNeeded = true; + stopFlag = false; + thread_ = std::thread(&ConnectivityMonitor::connectivityMonitorFunction, this); + threadRunning = true; + NMLOG_INFO("Connectivity monitor started with %d", timeout.load()); + } + + return true; + } + + bool ConnectivityMonitor::doInitialConnectivityMonitoring(int timeoutInSeconds) + { + if(!isConnectivityMonitorEndpointSet()) + { + NMLOG_INFO("Connectivity monitor endpoints are not set !"); + return false; + } + + if (isMonitorThreadRunning()) + { + NMLOG_INFO("Connectivity Monitor Thread is active so notify"); + cv_.notify_all(); + } + else + { + if (thread_.joinable()) + { + NMLOG_WARNING("Connectivity Monitor joinable Thread is active"); + stopFlag = true; + cv_.notify_all(); + thread_.join(); + } + + stopFlag = false; + timeout.store(timeoutInSeconds >= MONITOR_TIMEOUT_INTERVAL_MIN ? timeoutInSeconds:defaultTimeoutInSec); + thread_ = std::thread(&ConnectivityMonitor::connectivityMonitorFunction, this); + threadRunning = true; + NMLOG_INFO("Initial Connectivity Monitoring started with %d", timeout.load()); + } + + return true; + } + + bool ConnectivityMonitor::isMonitorThreadRunning() + { + return threadRunning.load(); + } + + bool ConnectivityMonitor::stopInitialConnectivityMonitoring() + { + if (isMonitorThreadRunning()) + { + if(isContinuesMonitoringNeeded) + { + NMLOG_WARNING("Continuous Connectivity Monitor is running"); + return true; + } + else + { + stopFlag = true; + cv_.notify_all(); + + if (thread_.joinable()) { + thread_.join(); + threadRunning = false; + NMLOG_INFO("Stoping Initial Connectivity Monitor"); + } + else + NMLOG_WARNING("thread not joinable !"); + } + } + else + NMLOG_WARNING("Continuous Connectivity Monitor not running"); + + return true; + } + + bool ConnectivityMonitor::stopContinuousConnectivityMonitoring() + { + if (!isMonitorThreadRunning()) + { + NMLOG_WARNING("Connectivity monitor not running"); + return false; + } + + cv_.notify_all(); + stopFlag = true; + + if (thread_.joinable()) + { + thread_.join(); + isContinuesMonitoringNeeded = false; + threadRunning = false; + NMLOG_INFO("Continuous Connectivity monitor stopped"); + } + else + NMLOG_WARNING("thread not joinable !"); + return true; + } + + void ConnectivityMonitor::signalConnectivityMonitor() + { + if (isMonitorThreadRunning()) + { + /* Reset the global value to UNKNOWN state*/ + resetConnectivityCache(); + cv_.notify_all(); + } + } + + void ConnectivityMonitor::connectivityMonitorFunction() + { + nsm_internetState InternetConnectionState = nsm_internetState::UNKNOWN; + do + { + InternetConnectionState = testConnectivity(getConnectivityMonitorEndpoints(), TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS, NSM_IPRESOLVE_WHATEVER); + if(g_internetState.load() != InternetConnectionState) + { + if(_instance != nullptr) + { + Exchange::INetworkManager::InternetStatus oldState = static_cast(g_internetState.load()); + Exchange::INetworkManager::InternetStatus newstate = static_cast(InternetConnectionState); + _instance->ReportInternetStatusChangedEvent(oldState , newstate); + NMLOG_TRACE("ReportInternetStatusChangedEvent called"); + } + else + NMLOG_WARNING("ReportInternetStatusChangedEvent callback not set"); + + g_internetState.store(InternetConnectionState); + } + + if(!isContinuesMonitoringNeeded && (g_internetState.load() == FULLY_CONNECTED)) + { + stopFlag = true; + NMLOG_INFO("Initial Connectivity Monitoring done Exiting ... Internet state FULLY_CONNECTED"); + threadRunning = false; + break; + } + + if(stopFlag) + { + NMLOG_WARNING("stopFlag true exiting"); + threadRunning = false; + break; + } + //wait for next timout or conditon signal + std::unique_lock lock(mutex_); + if (cv_.wait_for(lock, std::chrono::seconds(timeout.load())) == std::cv_status::timeout) + { + NMLOG_INFO("Connectivity monitor thread timeout"); + } + else + { + if(!stopFlag) + { + NMLOG_INFO("Connectivity monitor received a trigger"); + } + } + + } while (!stopFlag); + g_internetState = nsm_internetState::UNKNOWN; + NMLOG_WARNING("Connectivity monitor exiting"); + } + + } // namespace Plugin +} // namespace WPEFramework diff --git a/NetworkManager/service/NetworkConnectivity.h b/NetworkManager/service/NetworkConnectivity.h new file mode 100644 index 0000000000..8b2144093c --- /dev/null +++ b/NetworkManager/service/NetworkConnectivity.h @@ -0,0 +1,148 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "Module.h" +#include "NetworkManagerLogger.h" + +#define CAPTIVEPORTAL_MAX_LEN 512 +#define DEFAULT_MONITOR_TIMEOUT 60 // in seconds +#define MONITOR_TIMEOUT_INTERVAL_MIN 5 +#define TEST_CONNECTIVITY_DEFAULT_TIMEOUT_MS 4000 + +enum nsm_ipversion { + NSM_IPRESOLVE_WHATEVER = 0, /* default, resolves addresses to all IP*/ + NSM_IPRESOLVE_V4 = 1, /* resolve to IPv4 addresses */ + NSM_IPRESOLVE_V6 = 2 /* resolve to IPv6 addresses */ +}; + +enum nsm_internetState { + UNKNOWN = -1, + NO_INTERNET, + LIMITED_INTERNET, + CAPTIVE_PORTAL, + FULLY_CONNECTED +}; + +enum nsm_connectivity_httpcode { + HttpStatus_response_error = 99, + HttpStatus_200_OK = 200, + HttpStatus_204_No_Content = 204, + HttpStatus_301_Moved_Permanentl = 301, + HttpStatus_302_Found = 302, // captive portal + HttpStatus_307_Temporary_Redirect = 307, + HttpStatus_308_Permanent_Redirect = 308, + HttpStatus_403_Forbidden = 403, + HttpStatus_404_Not_Found = 404, + HttpStatus_511_Authentication_Required = 511 // captive portal RFC 6585 +}; + +namespace WPEFramework { + namespace Plugin { + + /* save user specific endponint in to a chache file and load form the file if monitorEndpoints are empty case wpeframework restared */ + class EndpointCache { + public: + static EndpointCache& getInstance() { + static EndpointCache instance; + return instance; + } + + bool isEndpointCashFileExist(); + void writeEnpointsToFile(const std::vector& endpoints); + std::vector readEnpointsFromFile(); + + private: + EndpointCache() : CachefilePath("/tmp/network.plugin.endpoints") {} + ~EndpointCache(){} + + std::string CachefilePath; + }; + + class Connectivity { + + Connectivity(const Connectivity&) = delete; + const Connectivity& operator=(const Connectivity&) = delete; + + public: + Connectivity(const std::string& configFilePath = "/etc/netsrvmgr.conf") + { + loadConnectivityConfig(configFilePath); + if(m_defaultEndpoints.empty()) + { + NMLOG_ERROR("NETSRVMGR CONFIGURATION ERROR: CONNECTIVITY ENDPOINT EMPTY"); + m_defaultEndpoints.clear(); + m_defaultEndpoints.push_back("http://clients3.google.com/generate_204"); + } + } + ~Connectivity(){} + + nsm_internetState testConnectivity(const std::vector& endpoints, long timeout_ms, nsm_ipversion ipversion); + std::vector getConnectivityDefaultEndpoints() { return m_defaultEndpoints; }; + std::string getCaptivePortal() { const std::lock_guard lock(capitiveMutex); return g_captivePortal; } + void setCaptivePortal(const char* captivePortal) {const std::lock_guard lock(capitiveMutex); g_captivePortal = captivePortal; } + + private: + void loadConnectivityConfig(const std::string& configFilePath); + nsm_internetState checkInternetStateFromResponseCode(const std::vector& responses); + + std::vector m_defaultEndpoints; + std::map configMap; + std::mutex capitiveMutex; + std::string g_captivePortal; + bool configMonitorConnectivityEnabled = false; + int configMonitorInterval = DEFAULT_MONITOR_TIMEOUT; + }; + + class ConnectivityMonitor : public Connectivity { + public: + bool isConnectedToInternet(nsm_ipversion ipversion); + nsm_internetState getInternetConnectionState(nsm_ipversion ipversion); + std::string getCaptivePortalURI(); + void setConnectivityMonitorEndpoints(const std::vector &endpoints); + std::vector getConnectivityMonitorEndpoints(); + bool doContinuousConnectivityMonitoring(int timeoutInSeconds); + bool doInitialConnectivityMonitoring(int timeoutInSeconds); + bool stopContinuousConnectivityMonitoring(); + bool stopInitialConnectivityMonitoring(); + bool isConnectivityMonitorEndpointSet(); + bool isMonitorThreadRunning(); + void signalConnectivityMonitor(); + void resetConnectivityCache() { g_internetState = nsm_internetState::UNKNOWN;} + + ConnectivityMonitor() : stopFlag(false), threadRunning(false), isContinuesMonitoringNeeded(false) + { + setConnectivityMonitorEndpoints(getConnectivityDefaultEndpoints()); + } + + ~ConnectivityMonitor() { + NMLOG_INFO("~ConnectivityMonitor"); + stopContinuousConnectivityMonitoring(); + } + + private: + ConnectivityMonitor(const ConnectivityMonitor&) = delete; + ConnectivityMonitor& operator=(const ConnectivityMonitor&) = delete; + void connectivityMonitorFunction(); + + EndpointCache& endpointCache = EndpointCache::getInstance(); + + std::thread thread_; + std::atomic stopFlag; + std::atomic threadRunning; + std::atomic isContinuesMonitoringNeeded; + std::condition_variable cv_; + std::atomic timeout; + std::vector monitorEndpoints; + const int defaultTimeoutInSec = DEFAULT_MONITOR_TIMEOUT; + std::mutex mutex_; + std::mutex endpointMutex; + std::atomic g_internetState = {nsm_internetState::UNKNOWN}; + }; + } // namespace Plugin +} // namespace WPEFramework diff --git a/NetworkManager/service/NetworkManager.conf.in b/NetworkManager/service/NetworkManager.conf.in new file mode 100644 index 0000000000..e81798a7b1 --- /dev/null +++ b/NetworkManager/service/NetworkManager.conf.in @@ -0,0 +1,26 @@ +autostart = "true" +callsign= "org.rdk.NetworkManager" + +test = JSON() +test.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") +test.add("outofprocess", "true") + +connectivity = JSON() +connectivity.add("endpoint_1", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_1@") +connectivity.add("endpoint_2", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_2@") +connectivity.add("endpoint_3", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_3@") +connectivity.add("endpoint_4", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_4@") +connectivity.add("endpoint_5", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_5@") +connectivity.add("interval", "@PLUGIN_NETWORKMANAGER_CONN_MONITOR_INTERVAL@") + +stun = JSON() +stun.add("endpoint", "@PLUGIN_NETWORKMANAGER_STUN_ENDPOINT@") +stun.add("port", "@PLUGIN_NETWORKMANAGER_STUN_PORT@") +stun.add("interval", "30") + +configuration = JSON() +configuration.add("root", test) +configuration.add("connectivity", connectivity) +configuration.add("stun", stun) +configuration.add("loglevel", "@PLUGIN_NETWORKMANAGER_LOGLEVEL@") + diff --git a/NetworkManager/service/NetworkManager.config b/NetworkManager/service/NetworkManager.config new file mode 100644 index 0000000000..da2a22c5c2 --- /dev/null +++ b/NetworkManager/service/NetworkManager.config @@ -0,0 +1,27 @@ +set(autostart true) +set(callsign "org.rdk.NetworkManager") + +map() + key(root) + map() + kv(outofprocess true) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() + key(connectivity) + map() + kv(endpoint_1 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_1}) + kv(endpoint_2 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_2}) + kv(endpoint_3 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_3}) + kv(endpoint_4 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_4}) + kv(endpoint_5 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_5}) + kv(interval, @PLUGIN_NETWORKMANAGER_CONN_MONITOR_INTERVAL@) + end() + key(stun) + map() + kv(endpoint, ${PLUGIN_NETWORKMANAGER_STUN_ENDPOINT}) + kv(port, PLUGIN_NETWORKMANAGER_STUN_PORT) + kv(interval, 30) + end() + kv(loglevel, 3) +end() +ans(configuration) diff --git a/NetworkManager/service/NetworkManager.cpp b/NetworkManager/service/NetworkManager.cpp new file mode 100644 index 0000000000..cb732430d7 --- /dev/null +++ b/NetworkManager/service/NetworkManager.cpp @@ -0,0 +1,169 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* 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 "NetworkManager.h" + +#include + +namespace WPEFramework +{ + namespace Plugin + { + static Plugin::Metadata metadata( + // Version (Major, Minor, Patch) + NETWORKMANAGER_MAJOR_VERSION, NETWORKMANAGER_MINOR_VERSION, NETWORKMANAGER_PATCH_VERSION, + // Preconditions + { subsystem::PLATFORM }, + // Terminations + {}, + // Controls + { subsystem::INTERNET } + ); + + NetworkManager::NetworkManager() + : _connectionId(0), + _service(nullptr), + _NetworkManager(nullptr), + _notification(this) + { + // Don't do any work in the constructor - all set up should be done in Initialize + } + + NetworkManager::~NetworkManager() + { + // Don't do any work in the constructor - all tear down should be done in Deinitialize + } + + /** + * Initialise the plugin and register ourselves + * + * This should aim to be as fast as possible + * + * Even if we're running in Out Of Process mode, this will still run in the + * main WPEFramework process - the new process is actually spawned from this method + */ + const string NetworkManager::Initialize(PluginHost::IShell *service) + { + // Make sure everything is null as we expect + ASSERT(_service == nullptr); + ASSERT(_NetworkManager == nullptr); + + // Syslog Startup messages are always printed by default + SYSLOG(Logging::Startup, (_T("Initializing NetworkManager"))); + SYSLOG(Logging::Startup, (_T("Initialize running in process %d"), Core::ProcessInfo().Id())); + NetworkManagerLogger::Init(); + // Register the Connection::Notification first. Do this before we start our actual plugin + // in case something goes wrong or is disconnected - this way we know we're at least registered + // for activate/deactivate events + _service = service; + _service->Register(&_notification); + + // Register ourselves in the PluginHost so other plugins know where to find us + // If we are running out of process (as per our config file), this is what will actually spawn the WPEProcess process + // which will run our plugin instance + // + // Ideally for large, complex plugins we would actually split the plugin into two libraries - a thin library that just calls + // _service->Root to launch WPEProcess, and a larger library that is only ever run inside WPEProcess only (we do this for Cobalt and WebKitBrowser) + _NetworkManager = service->Root(_connectionId, 5000, _T("NetworkManagerImplementation")); + + // Still running inside the main WPEFramework process - the child process will have now been spawned and registered if necessary + if (_NetworkManager != nullptr) + { + // set the plugin configuration + Exchange::INetworkManager::NMLogging _loglevel; + _NetworkManager->Configure(_service->ConfigLine(), _loglevel); + // configure loglevel in libWPEFrameworkNetworkManager.so + NetworkManagerLogger::SetLevel(static_cast (_loglevel)); + //Exchange::JNetworkManager::Register(*this, _NetworkManager); + _NetworkManager->Register(&_notification); + + // Register all custom JSON-RPC methods + RegisterAllMethods(); +#ifdef ENABLE_LEGACY_NSM_SUPPORT + RegisterLegacyMethods(); +#endif + } + else + { + // Something went wrong, clean up + TRACE(Trace::Error, (_T("Failed to initialize NetworkManager"))); + _service->Unregister(&_notification); + _service = nullptr; + + // Returning a string signals that we failed to initialize - WPEFramework will print this as an error message + return "Failed to initialize NetworkManager"; + } + + // Success + return ""; + } + + /** + * Clean up the plugin when we're deactivated. Should release any resources we were holding + * + * Note again this code runs inside the main WPEFramework daemon even if the plugin is set to run out-of-process + */ + void NetworkManager::Deinitialize(PluginHost::IShell *service) + { + ASSERT(_service == service); + ASSERT(_NetworkManager != nullptr); + + TRACE(Trace::Information, (_T("Deinitializing NetworkManager"))); + TRACE(Trace::Information, (_T("Deinitialize running in process %d"), Core::ProcessInfo().Id())); + + if (_NetworkManager != nullptr) + { + // TODO:: Work out exactly what triggers the shutdown of the out-of-process host + _service->Unregister(&_notification); + _NetworkManager->Unregister(&_notification); + + //Exchange::JNetworkManager::Unregister(*this); + // Unregister all our JSON-RPC methods + UnregisterAllMethods(); +#ifdef ENABLE_LEGACY_NSM_SUPPORT + UnregisterLegacyMethods(); +#endif + _NetworkManager->Release(); + } + + // Set everything back to default + _connectionId = 0; + _service = nullptr; + _NetworkManager = nullptr; + } + + string NetworkManager::Information() const + { + // No additional info to report + return string(); + } + + + void NetworkManager::Deactivated(RPC::IRemoteConnection *connection) + { + // Gracefully handle an unexpected termination from the other side of the connection (for example if the remote process crashed) + // and deactivate ourselves as we cannot continue safely + if (connection->Id() == _connectionId) + { + ASSERT(_service != nullptr); + Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); + } + } + } +} diff --git a/NetworkManager/service/NetworkManager.h b/NetworkManager/service/NetworkManager.h new file mode 100644 index 0000000000..d9d1171005 --- /dev/null +++ b/NetworkManager/service/NetworkManager.h @@ -0,0 +1,424 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ + +#pragma once + +#include "Module.h" + +// Include the interface we created +//#include +#include "INetworkManager.h" +#include "NetworkManagerLogger.h" + +#include +#include + +namespace WPEFramework +{ + namespace Plugin + { + /** + * NetworkManager plugin that exposes an API over both COM-RPC and JSON-RPC + * + */ + class NetworkManager : public PluginHost::IPlugin, public PluginHost::JSONRPC, public PluginHost::ISubSystem::IInternet + { + /** + * Our notification handling code + * + * Handle both the Activate/Deactivate notifications and provide a handler + * for notifications raised by the COM-RPC API + */ + class Notification : public RPC::IRemoteConnection::INotification, + public Exchange::INetworkManager::INotification + { + private: + Notification() = delete; + Notification(const Notification &) = delete; + Notification &operator=(const Notification &) = delete; + string InterfaceStateToString(Exchange::INetworkManager::InterfaceState event) + { + switch (event) + { + case Exchange::INetworkManager::INTERFACE_ADDED: + return "INTERFACE_ADDED"; + case Exchange::INetworkManager::INTERFACE_LINK_UP: + return "INTERFACE_LINK_UP"; + case Exchange::INetworkManager::INTERFACE_LINK_DOWN: + return "INTERFACE_LINK_DOWN"; + case Exchange::INetworkManager::INTERFACE_ACQUIRING_IP: + return "INTERFACE_ACQUIRING_IP"; + case Exchange::INetworkManager::INTERFACE_REMOVED: + return "INTERFACE_REMOVED"; + case Exchange::INetworkManager::INTERFACE_DISABLED: + return "INTERFACE_DISABLED"; + } + return ""; + } + + string WiFiSignalQualityToString(Exchange::INetworkManager::WiFiSignalQuality quality) + { + switch (quality) + { + case Exchange::INetworkManager::WiFiSignalQuality::WIFI_SIGNAL_DISCONNECTED: + return "Disconnected"; + case Exchange::INetworkManager::WiFiSignalQuality::WIFI_SIGNAL_WEAK: + return "Weak"; + case Exchange::INetworkManager::WiFiSignalQuality::WIFI_SIGNAL_FAIR: + return "Fair"; + case Exchange::INetworkManager::WiFiSignalQuality::WIFI_SIGNAL_GOOD: + return "Good"; + case Exchange::INetworkManager::WiFiSignalQuality::WIFI_SIGNAL_EXCELLENT: + return "Excellent"; + } + return ""; + } + + string InternetStatusToString(const Exchange::INetworkManager::InternetStatus internetStatus) + { + switch (internetStatus) + { + case Exchange::INetworkManager::InternetStatus::INTERNET_LIMITED: + return "LIMITED_INTERNET"; + case Exchange::INetworkManager::InternetStatus::INTERNET_CAPTIVE_PORTAL: + return "CAPTIVE_PORTAL"; + case Exchange::INetworkManager::InternetStatus::INTERNET_FULLY_CONNECTED: + return "FULLY_CONNECTED"; + default: + return "NO_INTERNET"; + } + return ""; + } + + public: + explicit Notification(NetworkManager *parent) + : _parent(*parent) + { + ASSERT(parent != nullptr); + } + virtual ~Notification() override + { + } + + public: + void onInterfaceStateChange(const Exchange::INetworkManager::InterfaceState event, const string interface) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonObject params; +#ifdef ENABLE_LEGACY_NSM_SUPPORT + JsonObject legacyParams; + JsonObject onConnParams; + std::string json; + if(interface == "wlan0") + legacyParams["interface"] = "WIFI"; + else if(interface == "eth0") + legacyParams["interface"] = "ETHERNET"; + if(event == Exchange::INetworkManager::INTERFACE_ADDED) + legacyParams["enabled"] = true; + else if(event == Exchange::INetworkManager::INTERFACE_REMOVED) + legacyParams["enabled"] = false; + _parent.Notify("onInterfaceStatusChanged", legacyParams); + if(event == Exchange::INetworkManager::INTERFACE_LINK_UP) + onConnParams["status"] = "CONNECTED"; + else if(event == Exchange::INetworkManager::INTERFACE_LINK_DOWN) + onConnParams["status"] = "DISCONNECTED"; + onConnParams["interface"] = legacyParams["interface"]; + onConnParams.ToString(json); + NMLOG_TRACE("onConnectionStatusChanged onConnParams=%s", json.c_str() ); + _parent.Notify("onConnectionStatusChanged", onConnParams); +#endif + params["interface"] = interface; + params["state"] = InterfaceStateToString(event); + _parent.Notify("onInterfaceStateChange", params); + } + + void onIPAddressChange(const string interface, const bool isAcquired, const bool isIPv6, const string ipAddress) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonObject params; +#ifdef ENABLE_LEGACY_NSM_SUPPORT + JsonObject legacyParams; + if(isIPv6) + { + legacyParams["ip6Address"] = ipAddress; + legacyParams["ip4Address"] = ""; + } + else + { + legacyParams["ip4Address"] = ipAddress; + legacyParams["ip6Address"] = ""; + } + if(interface == "wlan0") + legacyParams["interface"] = "WIFI"; + else if(interface == "eth0") + legacyParams["interface"] = "ETHERNET"; + legacyParams["status"] = string (isAcquired ? "ACQUIRED" : "LOST"); + _parent.Notify("onIPAddressStatusChanged", legacyParams); +#endif + params["status"] = string (isAcquired ? "ACQUIRED" : "LOST"); + params["interface"] = interface; + params["ipAddress"] = ipAddress; + params["isIPv6"] = isIPv6; + _parent.Notify("onIPAddressChange", params); + } + + void onActiveInterfaceChange(const string prevActiveInterface, const string currentActiveinterface) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonObject params; +#ifdef ENABLE_LEGACY_NSM_SUPPORT + JsonObject legacyParams; + string oldInterface; + string newInterface; + if(prevActiveInterface == "wlan0") + oldInterface = "WIFI"; + else if(prevActiveInterface == "eth0") + oldInterface = "ETHERNET"; + if(currentActiveinterface == "wlan0") + newInterface = "WIFI"; + else if(currentActiveinterface == "eth0") + newInterface = "ETHERNET"; + legacyParams["oldInterfaceName"] = oldInterface; + legacyParams["newInterfaceName"] = newInterface; + _parent.Notify("onDefaultInterfaceChanged", legacyParams); +#endif + params["oldInterfaceName"] = prevActiveInterface; + params["newInterfaceName"] = currentActiveinterface; + _parent.Notify("onActiveInterfaceChange", params); + + } + + void onInternetStatusChange(const Exchange::INetworkManager::InternetStatus oldState, const Exchange::INetworkManager::InternetStatus newstate) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonObject params; + + params["state"] = static_cast (newstate);; + params["status"] = InternetStatusToString(newstate); + params["prevState"] = static_cast (oldState); + params["prevStatus"] = InternetStatusToString(oldState); + + _parent.Notify("onInternetStatusChange", params); + + if (Exchange::INetworkManager::InternetStatus::INTERNET_FULLY_CONNECTED == newstate) + { + NMLOG_INFO("Notify Thunder ISubsystem internet"); + _parent.PublishToThunderAboutInternet(); + } + } + + // WiFi Notifications that other processes can subscribe to + void onAvailableSSIDs(const string jsonOfWiFiScanResults) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonArray scanResults; + JsonObject result; + scanResults.FromString(jsonOfWiFiScanResults); + result["ssids"] = scanResults; + _parent.Notify("onAvailableSSIDs", result); + + } + + void onWiFiStateChange(const Exchange::INetworkManager::WiFiState state) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonObject result; +#ifdef ENABLE_LEGACY_NSM_SUPPORT + JsonObject legacyResult; + legacyResult["state"] = static_cast (state); + legacyResult["isLNF"] = false; + _parent.Notify("onWIFIStateChanged", legacyResult); +#endif + result["state"] = static_cast (state); + _parent.Notify("onWiFiStateChange", result); + } + + void onWiFiSignalStrengthChange(const string ssid, const string signalLevel, const Exchange::INetworkManager::WiFiSignalQuality signalQuality) override + { + NMLOG_TRACE("%s", __FUNCTION__); + JsonObject result; +#ifdef ENABLE_LEGACY_NSM_SUPPORT + JsonObject legacyResult; + legacyResult["signalStrength"] = WiFiSignalQualityToString(signalQuality); + legacyResult["strength"] = signalLevel; + _parent.Notify("onWifiSignalThresholdChanged", legacyResult); +#endif + result["ssid"] = ssid; + result["signalQuality"] = WiFiSignalQualityToString(signalQuality); + result["signalLevel"] = signalLevel; + _parent.Notify("onWiFiSignalStrengthChange", result); + } + + // The activated/deactived methods are part of the RPC::IRemoteConnection::INotification + // interface. These are triggered when Thunder detects a connection/disconnection over the + // COM-RPC link. + void Activated(RPC::IRemoteConnection * /* connection */) override + { + } + + void Deactivated(RPC::IRemoteConnection *connection) override + { + // Something's caused the remote connection to be lost - this could be a crash + // on the remote side so deactivate ourselves + _parent.Deactivated(connection); + } + + // Build QueryInterface implementation, specifying all possible interfaces we implement + BEGIN_INTERFACE_MAP(Notification) + INTERFACE_ENTRY(Exchange::INetworkManager::INotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP + + private: + NetworkManager &_parent; + }; + + public: + NetworkManager(); + ~NetworkManager() override; + + // Implement the basic IPlugin interface that all plugins must implement + const string Initialize(PluginHost::IShell *service) override; + void Deinitialize(PluginHost::IShell *service) override; + string Information() const override; + + // Do not allow copy/move constructors + NetworkManager(const NetworkManager &) = delete; + NetworkManager &operator=(const NetworkManager &) = delete; + + // Build QueryInterface implementation, specifying all possible interfaces we implement + // This is necessary so that consumers can discover which plugin implements what interface + BEGIN_INTERFACE_MAP(NetworkManager) + + // Which interfaces do we implement? + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_ENTRY(PluginHost::ISubSystem::IInternet) + + // We need to tell Thunder that this plugin provides the INetworkManager interface, but + // since it's not actually implemented here we tell Thunder where it can + // find the real implementation + // This allows other components to call QueryInterface() and + // receive the actual implementation (which could be in-process or out-of-process) + INTERFACE_AGGREGATE(Exchange::INetworkManager, _NetworkManager) + END_INTERFACE_MAP + + /* + * ------------------------------------------------------------------------------------------------------------ + * ISubSystem::IInternet methods + * ------------------------------------------------------------------------------------------------------------ + */ + string PublicIPAddress() const override + { + return m_publicIPAddress; + } + network_type NetworkType() const override + { + return (m_publicIPAddress.empty() == true ? PluginHost::ISubSystem::IInternet::UNKNOWN : (m_publicIPAddressType == "IPV6" ? PluginHost::ISubSystem::IInternet::IPV6 : PluginHost::ISubSystem::IInternet::IPV4)); + } + void PublishToThunderAboutInternet(); + + private: + // Notification/event handlers + // Clean up when we're told to deactivate + void Deactivated(RPC::IRemoteConnection *connection); + + // JSON-RPC setup + void RegisterAllMethods(); + void UnregisterAllMethods(); +#ifdef ENABLE_LEGACY_NSM_SUPPORT + void RegisterLegacyMethods(); + void UnregisterLegacyMethods(); +#endif + + // JSON-RPC methods (take JSON in, spit JSON back out) + uint32_t SetLogLevel (const JsonObject& parameters, JsonObject& response); + uint32_t GetAvailableInterfaces (const JsonObject& parameters, JsonObject& response); + uint32_t GetPrimaryInterface (const JsonObject& parameters, JsonObject& response); + uint32_t SetPrimaryInterface (const JsonObject& parameters, JsonObject& response); + uint32_t EnableInterface (const JsonObject& parameters, JsonObject& response); + uint32_t DisableInterface (const JsonObject& parameters, JsonObject& response); + uint32_t GetIPSettings(const JsonObject& parameters, JsonObject& response); + uint32_t SetIPSettings(const JsonObject& parameters, JsonObject& response); + uint32_t GetStunEndpoint(const JsonObject& parameters, JsonObject& response); + uint32_t SetStunEndpoint(const JsonObject& parameters, JsonObject& response); + uint32_t GetConnectivityTestEndpoints(const JsonObject& parameters, JsonObject& response); + uint32_t SetConnectivityTestEndpoints(const JsonObject& parameters, JsonObject& response); + uint32_t IsConnectedToInternet(const JsonObject& parameters, JsonObject& response); + uint32_t GetCaptivePortalURI(const JsonObject& parameters, JsonObject& response); + uint32_t StartConnectivityMonitoring(const JsonObject& parameters, JsonObject& response); + uint32_t StopConnectivityMonitoring(const JsonObject& parameters, JsonObject& response); + uint32_t GetPublicIP(const JsonObject& parameters, JsonObject& response); + uint32_t Ping(const JsonObject& parameters, JsonObject& response); + uint32_t Trace(const JsonObject& parameters, JsonObject& response); + uint32_t StartWiFiScan(const JsonObject& parameters, JsonObject& response); + uint32_t StopWiFiScan(const JsonObject& parameters, JsonObject& response); + uint32_t GetKnownSSIDs(const JsonObject& parameters, JsonObject& response); + uint32_t AddToKnownSSIDs(const JsonObject& parameters, JsonObject& response); + uint32_t RemoveKnownSSID(const JsonObject& parameters, JsonObject& response); + uint32_t WiFiConnect(const JsonObject& parameters, JsonObject& response); + uint32_t WiFiDisconnect(const JsonObject& parameters, JsonObject& response); + uint32_t GetConnectedSSID(const JsonObject& parameters, JsonObject& response); + uint32_t StartWPS(const JsonObject& parameters, JsonObject& response); + uint32_t StopWPS(const JsonObject& parameters, JsonObject& response); + uint32_t GetWifiState(const JsonObject& parameters, JsonObject& response); + uint32_t GetWiFiSignalStrength(const JsonObject& parameters, JsonObject& response); + uint32_t GetSupportedSecurityModes(const JsonObject& parameters, JsonObject& response); +#ifdef ENABLE_LEGACY_NSM_SUPPORT + uint32_t getInterfaces (const JsonObject& parameters, JsonObject& response); + uint32_t isInterfaceEnabled (const JsonObject& parameters, JsonObject& response); + uint32_t setInterfaceEnabled (const JsonObject& parameters, JsonObject& response); + uint32_t getPublicIP (const JsonObject& parameters, JsonObject& response); + uint32_t getDefaultInterface(const JsonObject& parameters, JsonObject& response); + uint32_t setDefaultInterface(const JsonObject& parameters, JsonObject& response); + uint32_t setIPSettings(const JsonObject& parameters, JsonObject& response); + uint32_t getIPSettings(const JsonObject& parameters, JsonObject& response); + uint32_t getInternetConnectionState(const JsonObject& parameters, JsonObject& response); + uint32_t ping(const JsonObject& parameters, JsonObject& response); + uint32_t isConnectedToInternet(const JsonObject& parameters, JsonObject& response); + uint32_t setConnectivityTestEndpoints(const JsonObject& parameters, JsonObject& response); + uint32_t startConnectivityMonitoring(const JsonObject& parameters, JsonObject& response); + uint32_t getCaptivePortalURI(const JsonObject& parameters, JsonObject& response); + uint32_t stopConnectivityMonitoring(const JsonObject& parameters, JsonObject& response); + uint32_t getPairedSSID(const JsonObject& parameters, JsonObject& response); + uint32_t getPairedSSIDInfo(const JsonObject& parameters, JsonObject& response); + uint32_t initiateWPSPairing(const JsonObject& parameters, JsonObject& response); + uint32_t isPaired(const JsonObject& parameters, JsonObject& response); + uint32_t saveSSID(const JsonObject& parameters, JsonObject& response); + uint32_t cancelWPSPairing(const JsonObject& parameters, JsonObject& response); + uint32_t clearSSID(const JsonObject& parameters, JsonObject& response); + uint32_t connect(const JsonObject& parameters, JsonObject& response); + uint32_t disconnect(const JsonObject& parameters, JsonObject& response); + uint32_t getConnectedSSID(const JsonObject& parameters, JsonObject& response); + uint32_t getSupportedSecurityModes(const JsonObject& parameters, JsonObject& response); + uint32_t startScan(const JsonObject& parameters, JsonObject& response); + uint32_t stopScan(const JsonObject& parameters, JsonObject& response); + uint32_t getCurrentState(const JsonObject& parameters, JsonObject& response); +#endif + private: + uint32_t _connectionId; + PluginHost::IShell *_service; + Exchange::INetworkManager *_NetworkManager; + Core::Sink _notification; + string m_publicIPAddress; + string m_defaultInterface; + string m_publicIPAddressType; + }; + } +} diff --git a/NetworkManager/service/NetworkManager.json b/NetworkManager/service/NetworkManager.json new file mode 100644 index 0000000000..064dedd2e6 --- /dev/null +++ b/NetworkManager/service/NetworkManager.json @@ -0,0 +1,1510 @@ +{ + "$schema": "https://raw.githubusercontent.com/rdkcentral/rdkservices/main/Tools/json_generator/schemas/interface.schema.json", + "jsonrpc": "2.0", + "info": { + "title": "NetworkManager Plugin", + "class": "NetworkManager", + "callsign": "org.rdk.NetworkManager", + "locator": "libWPEFrameworkNetworkManager.so", + "status": "production", + "description": "A Unified `NetworkManager` plugin that allows you to manage Ethernet and Wifi interfaces on the device.", + "version": "0.1.0" + }, + "common": { + "$ref": "../../common/common.json" + }, + "definitions": { + "interface": { + "summary": "An interface, such as `eth0` or `wlan0`, depending upon availability of the given interface", + "type": "string", + "example": "wlan0" + }, + "ipversion": { + "summary": "either IPv4 or IPv6", + "type": "string", + "example": "IPv4" + }, + "autoconfig": { + "summary": "`true` if DHCP is used, `false` if IP is configured manually", + "type": "boolean", + "example": true + }, + "dhcpserver": { + "summary": "The DHCP Server address", + "type": "string", + "example": "192.168.1.1" + }, + "ipaddress": { + "summary": "The IP address", + "type": "string", + "example": "192.168.1.101" + }, + "prefix": { + "summary": "The prefix number", + "type": "integer", + "example": 24 + }, + "v6LinkLocal": { + "summary": "The v6LinkLocal", + "type": "string", + "example": "192.168.1.1" + }, + "gateway": { + "summary": "The gateway address", + "type": "string", + "example": "192.168.1.1" + }, + "primarydns": { + "summary": "The primary DNS address", + "type": "string", + "example": "192.168.1.1" + }, + "secondarydns": { + "summary": "The secondary DNS address", + "type": "string", + "example": "192.168.1.2" + }, + "port":{ + "summary": "STUN server port", + "type": "integer", + "example": "3478" + }, + "endPoint":{ + "summary": "STUN server endPoint", + "type": "string", + "example": "stun.l.google.com" + }, + "endpoint":{ + "summary": "The host name or IP address", + "type": "string", + "example": "45.57.221.20" + }, + "bindTimeout":{ + "summary": "STUN server bind timeout", + "type": "integer", + "example": "30" + }, + "cacheTimeout":{ + "summary": "STUN server cache timeout", + "type": "integer", + "example": "0" + }, + "state": { + "summary": "The internet state", + "type": "integer", + "example": 4 + }, + "guid": { + "summary": "The globally unique identifier", + "type": "string", + "example": "" + }, + "noOfRequest": { + "summary": "The number of packets to send. Default is 15.", + "type": "integer", + "example": 10 + }, + "timeout":{ + "summary": "Timeout", + "type": "integer", + "example": "30" + }, + "ssid":{ + "summary": "The paired SSID", + "type": "string", + "example": "123412341234" + }, + "bssid":{ + "summary": "The paired BSSID", + "type": "string", + "example": "ff:ff:ff:ff:ff:ff" + }, + "passphrase": { + "summary": "The access point password", + "type": "string", + "example": "password" + }, + "securityMode": { + "summary": "The security mode. See `getSupportedSecurityModes`.", + "type": "integer", + "example": 6 + }, + "signalStrength":{ + "summary": "The RSSI value in dBm", + "type": "string", + "example": "-27.000000" + }, + "frequency":{ + "summary": "The supported frequency for this SSID in GHz", + "type": "string", + "example": "2.442000" + }, + "errors": { + "summary": "Error string of scan failure", + "type": "string", + "example": "" + }, + "empty_string": { + "summary": "Not supported", + "type": "string", + "example": "" + } + }, + "methods": { + "GetAvailableInterfaces":{ + "summary": "Get device supported list of available interface including their state.", + "result": { + "type": "object", + "properties": { + "Interfaces": { + "summary": "An interface", + "type":"array", + "items": { + "type":"object", + "properties": { + "type":{ + "summary": "Interface Type", + "type": "string", + "example": "ETHERNET" + }, + "name":{ + "summary": "Interface Name. ex: eth0 or wlan0", + "type": "string", + "example": "eth0" + }, + "mac":{ + "summary": "Interface MAC address", + "type": "string", + "example": "AA:AA:AA:AA:AA:AA" + }, + "isEnabled":{ + "summary": "Whether the interface is currently enabled", + "type": "boolean", + "example": true + }, + "isConnected":{ + "summary": "Whether the interface is currently connected", + "type": "boolean", + "example": true + } + }, + "required": [ + "type", + "name", + "mac", + "isEnabled", + "isConnected" + ] + } + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "interfaces", + "success" + ] + } + }, + "GetPrimaryInterface": { + "summary": "Gets the primary/default network interface for the device. The active network interface is defined as the one that can make requests to the external network. Returns one of the supported interfaces as per `GetAvailableInterfaces`, or an empty value which indicates that there is no default network interface.", + "result": { + "type": "object", + "properties": { + "interface": { + "$ref": "#/definitions/interface" + } + }, + "required": [ + "interface" + ] + } + }, + "SetPrimaryInterface":{ + "summary": "Sets the primary/default interface for the device. This call fails if the interface is not enabled.", + "events":{ + "onActiveInterfaceChange" : "Triggered when device’s default interface changed.", + "onInterfaceStateChange" : "Triggered when interface’s state changed", + "onAddressChange" : "Triggered when the device connects to router.", + "onInternetStatusChange" : "Triggered when each IP address is lost or acquired." + }, + "params": { + "type":"object", + "properties": { + "interface": { + "$ref": "#/definitions/interface" + } + }, + "required": [ + "interface" + ] + }, + "result": { + "$ref": "#/common/result" + } + }, + "GetIPSettings":{ + "summary": "Gets the IP setting for the given interface.", + "params": { + "type":"object", + "properties": { + "interface": { + "$ref": "#/definitions/interface" + }, + "ipversion": { + "$ref": "#/definitions/ipversion" + } + }, + "required": [ + "interface" + ] + }, + "result": { + "type": "object", + "properties": { + "interface": { + "$ref": "#/definitions/interface" + }, + "ipversion": { + "$ref": "#/definitions/ipversion" + }, + "autoconfig": { + "$ref": "#/definitions/autoconfig" + }, + "dhcpserver": { + "$ref": "#/definitions/dhcpserver" + }, + "ipaddress": { + "$ref": "#/definitions/ipaddress" + }, + "prefix": { + "$ref": "#/definitions/prefix" + }, + "gateway": { + "$ref": "#/definitions/gateway" + }, + "v6LinkLocal": { + "$ref": "#/definitions/v6LinkLocal" + }, + "primarydns": { + "$ref": "#/definitions/primarydns" + }, + "secondarydns": { + "$ref": "#/definitions/secondarydns" + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "interface", + "ipversion", + "autoconfig", + "ipaddress", + "prefix", + "v6LinkLocal", + "gateway", + "primarydns", + "secondarydns", + "success" + ] + } + }, + "SetIPSettings":{ + "summary": "Sets the IP settings for the given interface.", + "events":{ + "onAddressChange" : "Triggered when the device connects to router.", + "onInternetStatusChange" : "Triggered when each IP address is lost or acquired." + }, + "params": { + "type":"object", + "properties": { + "interface": { + "$ref": "#/definitions/interface" + }, + "ipversion": { + "$ref": "#/definitions/ipversion" + }, + "autoconfig": { + "$ref": "#/definitions/autoconfig" + }, + "ipaddress": { + "$ref": "#/definitions/ipaddress" + }, + "prefix": { + "$ref": "#/definitions/prefix" + }, + "gateway": { + "$ref": "#/definitions/gateway" + }, + "primarydns": { + "$ref": "#/definitions/primarydns" + }, + "secondarydns": { + "$ref": "#/definitions/secondarydns" + } + }, + "required": [ + "interface", + "ipversion", + "autoconfig", + "ipaddress", + "prefix", + "gateway", + "primarydns", + "secondarydns" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "GetStunEndpoint": { + "summary": "Get the STUN Endpoint that is used to identify public IP of the device.", + "result": { + "type": "object", + "properties": { + "endPoint": { + "$ref": "#/definitions/endPoint" + }, + "port": { + "$ref": "#/definitions/port" + }, + "bindTimeout": { + "$ref": "#/definitions/bindTimeout" + }, + "cacheTimeout": { + "$ref": "#/definitions/cacheTimeout" + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "endPoint", + "port", + "bindTimeout", + "cacheTimeout", + "success" + ] + } + }, + "SetStunEndpoint":{ + "summary": "Set the STUN Endpoint to be used to identify public IP of the device.", + "params": { + "type":"object", + "properties": { + "endPoint": { + "$ref": "#/definitions/endPoint" + }, + "port": { + "$ref": "#/definitions/port" + }, + "bindTimeout": { + "$ref": "#/definitions/bindTimeout" + }, + "cacheTimeout": { + "$ref": "#/definitions/cacheTimeout" + } + }, + "required": [ + "endPoint", + "port" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "public_ip", + "success" + ] + } + }, + "GetConnectivityTestEndpoints":{ + "summary": "Gets currently used test endpoints. on success list out the connectivity test points connections.", + "result": { + "type":"object", + "properties": { + "endpoints": { + "summary": "", + "type": "array", + "items": { + "type": "string", + "example": "http://clients3.google.com/generate_204" + } + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "endpoints", + "success" + ] + } + }, + "SetConnectivityTestEndpoints":{ + "summary": "This method used to set up to 5 endpoints for a connectivity test. Successful connections are verified with HTTP Status code 204 (No Content).", + "params": { + "type":"object", + "properties": { + "endpoints": { + "summary": "A list of endpoints to test", + "type": "array", + "items": { + "type": "string", + "example": "http://clients3.google.com/generate_204" + } + } + }, + "required": [ + "endpoints" + ] + }, + "result": { + "$ref": "#/common/result" + } + }, + "IsConnectedToInternet":{ + "summary": "Seeks Whether the device has internet connectivity. This API might take up to 3s to validate internet connectivity.", + "params": { + "type":"object", + "properties": { + "ipversion": { + "$ref": "#/definitions/ipversion" + } + } + }, + "result": { + "type": "object", + "properties": { + "isConnectedToInternet": { + "summary": "`true` if internet connectivity is detected, otherwise `false`", + "type": "boolean", + "example": true + }, + "internetState": { + "$ref": "#/definitions/state" + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "isConnectedToInternet", + "internetState", + "success" + ] + } + }, + "GetCaptivePortalURI":{ + "summary": "Gets the captive portal URI if connected to any captive portal network.", + "result": { + "type": "object", + "properties": { + "uri": { + "summary": "Captive portal URI", + "type": "string", + "example": "http://10.0.0.1/captiveportal.jst" + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "uri", + "success" + ] + } + }, + "StartConnectivityMonitoring":{ + "summary": "Enable a continuous monitoring of internet connectivity with heart beat interval thats given. If the monitoring is already happening, it will be restarted with new given interval.", + "events":{ + "onInternetStatusChange" : "Triggered when internet connection state changed." + }, + "params": { + "type":"object", + "properties": { + "interval": { + "summary": "Interval in sec.", + "type": "number", + "example": "30" + } + }, + "required": [ + "interval" + ] + }, + "result": { + "type": "object", + "properties": { + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "StopConnectivityMonitoring":{ + "summary": "Stops the connectivity monitoring", + "result": { + "type": "object", + "properties": { + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "GetPublicIP":{ + "summary": "Gets the internet/public IP Address of the device.", + "params": { + "type":"object", + "summary":"it allows empty parameter too", + "properties": { + "ipversion": { + "$ref": "#/definitions/ipversion" + } + }, + "required": [ + "ipversion" + ] + }, + "result": { + "type": "object", + "properties": { + "publicIP":{ + "summary": "Returns an public ip of the device", + "type":"string", + "example": "69.136.49.95" + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "publicIP", + "success" + ] + } + }, + "Ping":{ + "summary": "Pings the specified endpoint with the specified number of packets.", + "params": { + "type":"object", + "properties": { + "endpoint":{ + "$ref": "#/definitions/endpoint" + }, + "ipversion": { + "$ref": "#/definitions/ipversion" + }, + "noOfRequest": { + "$ref": "#/definitions/noOfRequest" + }, + "timeout": { + "$ref": "#/definitions/timeout" + }, + "guid": { + "$ref": "#/definitions/guid" + } + }, + "required": [ + "endpoint", + "ipversion", + "noOfRequest", + "timeout", + "guid" + ] + }, + "result": { + "type": "object", + "properties": { + "target": { + "summary": "The target IP address", + "type": "string", + "example": "45.57.221.20" + }, + "packetsTransmitted": { + "summary": "The number of packets sent", + "type": "integer", + "example": 10 + }, + "packetsReceived": { + "summary": "The number of packets received", + "type": "integer", + "example": 10 + }, + "packetLoss": { + "summary": "The number of packets lost", + "type": "string", + "example": "0.0" + }, + "tripMin": { + "summary": "The minimum amount of time to receive the packets", + "type": "string", + "example": "61.264" + }, + "tripAvg": { + "summary": "The average time to receive the packets", + "type": "string", + "example": "130.397" + }, + "tripMax": { + "summary": "The maximum amount of time to receive the packets", + "type": "string", + "example": "230.832" + }, + "tripStdDev": { + "summary": "The standard deviation for the trip", + "type": "string", + "example": "80.919" + }, + "error": { + "summary": "An error message", + "type": "string", + "example": "..." + }, + "guid": { + "summary": "The globally unique identifier", + "type": "string", + "example": "..." + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "target", + "packetsTransmitted", + "packetsReceived", + "packetLoss", + "tripMin", + "tripAvg", + "tripMax", + "tripStdDev", + "error", + "guid", + "success" + ] + } + }, + "Trace":{ + "summary": "Traces the specified endpoint with the specified number of packets using `traceroute`.", + "onTraceResponse":{ + "onPingResponse" : "Triggered when Trace request get success." + }, + "params": { + "type":"object", + "properties": { + "endpoint":{ + "$ref": "#/definitions/endpoint" + }, + "ipversion": { + "$ref": "#/definitions/ipversion" + }, + "noOfRequest": { + "$ref": "#/definitions/noOfRequest" + }, + "guid": { + "$ref": "#/definitions/guid" + } + }, + "required": [ + "endpoint", + "ipversion", + "noOfRequest", + "guid" + ] + }, + "result": { + "type": "object", + "properties": { + "target": { + "summary": "The target IP address", + "type": "string", + "example": "45.57.221.20" + }, + "packetsTransmitted": { + "summary": "The number of packets sent", + "type": "integer", + "example": 10 + }, + "packetsReceived": { + "summary": "The number of packets received", + "type": "integer", + "example": 10 + }, + "packetLoss": { + "summary": "The number of packets lost", + "type": "string", + "example": "0.0" + }, + "tripMin": { + "summary": "The minimum amount of time to receive the packets", + "type": "string", + "example": "61.264" + }, + "tripAvg": { + "summary": "The average time to receive the packets", + "type": "string", + "example": "130.397" + }, + "tripMax": { + "summary": "The maximum amount of time to receive the packets", + "type": "string", + "example": "230.832" + }, + "tripStdDev": { + "summary": "The standard deviation for the trip", + "type": "string", + "example": "80.919" + }, + "error": { + "summary": "An error message", + "type": "string", + "example": "..." + }, + "guid": { + "summary": "The globally unique identifier", + "type": "string", + "example": "..." + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "target", + "packetsTransmitted", + "packetsReceived", + "packetLoss", + "tripMin", + "tripAvg", + "tripMax", + "tripStdDev", + "error", + "guid", + "success" + ] + } + }, + "StartWiFiScan":{ + "summary": "Initiates WiFi scaning. This method supports scanning for specific range of frequency like 2.4GHz only or 5GHz only or 6GHz only or ALL. When no input passed about the frequency to be scanned, it scans for all. It publishes 'onAvailableSSIDs' event upon completion.", + "events": { + "onAvailableSSIDs" : "Triggered when list of SSIDs is available after the scan completes." + }, + "params": { + "type": "object", + "properties": { + "frequency": { + "summary": "The frequency to scan. An empty or `null` value scans all frequencies. If a frequency is specified (2.4 or 5.0), then the results are only returned for matching frequencies.", + "type": "string", + "example": "" + } + }, + "required": [ + "frequency" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "StopWiFiScan":{ + "summary": "Stops WiFi scanning. Any discovered SSIDs from the call to the `StartWiFiScan` method up to the point where this method is called are still returned as event.", + "result": { + "$ref": "#/common/result" + } + }, + "GetKnownSSIDs":{ + "summary": "Gets list of saved SSIDs. This method returns all the SSIDs that are saved as array.", + "result": { + "type": "object", + "properties": { + "ssids": { + "summary": "Known SSIDS", + "type": "array", + "items": { + "type": "string", + "example": "Xfinity_Guest" + } + }, + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "ssids", + "success" + ] + } + }, + "AddToKnownSSIDs":{ + "summary": "Saves the SSID, passphrase, and security mode for upcoming and future sessions. This method only adds to the persistent memory; does not disconnect from currently connected SSID.", + "params": { + "type": "object", + "properties": { + "ssid": { + "$ref": "#/definitions/ssid" + }, + "passphrase": { + "$ref": "#/definitions/passphrase" + }, + "securityMode": { + "$ref": "#/definitions/securityMode" + } + }, + "required": [ + "ssid", + "passphrase", + "securityMode" + ] + }, + "result": { + "type": "object", + "properties": { + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "RemoveKnownSSID":{ + "summary": "Remove given SSID from saved SSIDs. This method just removes from the list and of the list is having only one entry thats being removed, it will initiate a disconnect.", + "events":{ + "onWiFiStateChange" : "Triggered when Wifi state changes to DISCONNECTED", + "onAddressChange" : "Triggered when an IP Address is assigned or lost", + "onInternetStatusChange" : "Triggered when internet connection state changed" + }, + "params": { + "type": "object", + "properties": { + "ssid": { + "$ref": "#/definitions/ssid" + } + }, + "required": [ + "ssid" + ] + }, + "result": { + "type": "object", + "properties": { + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "WiFiConnect":{ + "summary": "Initiates request to connect to the specified SSID with the given passphrase. Passphrase can be `null` when the network security is `NONE`. When called with no arguments, this method attempts to connect to the saved SSID and password. See `AddToKnownSSIDs`.", + "events":{ + "onWiFiStateChange" : "Triggered when Wifi state changes to CONNECTING, CONNECTED ." + }, + "params": { + "type": "object", + "properties": { + "ssid": { + "$ref": "#/definitions/ssid" + }, + "passphrase": { + "$ref": "#/definitions/passphrase" + }, + "securityMode": { + "$ref": "#/definitions/securityMode" + } + }, + "required": [ + "ssid", + "passphrase", + "securityMode" + ] + }, + "result": { + "$ref": "#/common/result" + } + }, + "WiFiDisconnect":{ + "summary": "Disconnects from the currently connected SSID. A event will be posted upon completion", + "events":{ + "onWIFIStateChange" : "Triggered when Wifi state changes to DISCONNECTED (only if currently connected).", + "onAddressChange" : "Triggered when an IP Address is assigned or lost", + "onInternetStatusChange" : "Triggered when internet connection state changed" + }, + "result": { + "type": "object", + "properties": { + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "GetConnectedSSID":{ + "summary": "Returns the connected SSID information.", + "result": { + "type": "object", + "properties": { + "ssid": { + "$ref": "#/definitions/ssid" + }, + "bssid": { + "$ref": "#/definitions/bssid" + }, + "securityMode":{ + "summary": "The security mode. See the `connect` method", + "type": "string", + "example": "5" + }, + "signalStrength": { + "$ref": "#/definitions/signalStrength" + }, + "frequency": { + "$ref": "#/definitions/frequency" + }, + "rate":{ + "summary": "The physical data rate in Mbps", + "type": "string", + "example": "144.000000" + }, + "noise":{ + "summary": "The average noise strength in dBm", + "type": "string", + "example": "-121.000000" + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "ssid", + "bssid", + "rate", + "noise", + "securityMode", + "signalStrength", + "frequency", + "success" + ] + } + }, + "StartWPS":{ + "summary": "Initiates a connection using Wifi Protected Setup (WPS). An existing connection will be disconnected before attempting to initiate a new connection. Failure in WPS pairing will trigger an error event.\n\nIf the `method` parameter is set to `SERIALIZED_PIN`, then RDK retrieves the serialized pin using the Manufacturer (MFR) API. If the `method` parameter is set to `PIN`, then RDK use the pin supplied as part of the request. If the `method` parameter is set to `PBC`, then RDK uses Push Button Configuration (PBC) to obtain the pin.", + "events":{ + "onWIFIStateChange" : "Triggered when Wifi state changes to DISCONNECTED (only if currently connected), CONNECTING, CONNECTED.", + "onAddressChange" : "Triggered when an IP Address is assigned or lost", + "onInternetStatusChange" : "Triggered when internet connection state changed" + }, + "params": { + "type": "object", + "properties": { + "method": { + "summary": "The method used to obtain the pin (must be one of the following: PBC=0, PIN=1, SERIALIZED_PIN=2)", + "type": "integer", + "example": 1 + }, + "wps_pin": { + "summary": "A valid 8 digit WPS pin number. Use this parameter when the `method` parameter is set to `PIN`.", + "type": "string", + "example": "88888888" + } + }, + "required": [ + "method", + "wps_pin" + ] + }, + "result": { + "type": "object", + "properties": { + "pin": { + "summary": "The WPS pin value. Valid only when `method` is set to `PIN` or `SERIALIZED_PIN`.", + "type":"string", + "example": "88888888" + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "result", + "success" + ] + } + }, + "StopWPS":{ + "summary": "Cancels the in-progress WPS pairing operation. The operation forcefully stops the in-progress pairing attempt and aborts the current scan. WPS pairing must be in-progress for the operation to succeed.", + "events":{ + "onWIFIStateChange" : "Triggered when Wifi state changes to DISCONNECTED." + }, + "result": { + "type": "object", + "properties": { + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "GetWiFiSignalStrength":{ + "summary": "Get WiFiSignalStrength of connected SSID.", + "events":{ + "onWiFiSignalStrengthChange" : "Triggered when Wifi signal strength switches between Excellent, Good, Fair, Weak." + }, + "result": { + "type": "object", + "properties": { + "ssid": { + "$ref": "#/definitions/ssid" + }, + "signalStrength": { + "$ref": "#/definitions/signalStrength" + }, + "quality":{ + "summary": "Signal strength Quality", + "type": "integer", + "example": 123 + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "ssid", + "signalStrength", + "quality", + "success" + ] + } + }, + "GetSupportedSecurityModes":{ + "summary": "Returns the Wifi security modes that the device supports.", + "result": { + "type": "object", + "properties": { + "security_modes": { + "summary": "The supported security modes and its associated integer value.", + "type": "object", + "properties": { + "NET_WIFI_SECURITY_NONE": { + "type": "integer", + "example": 0 + }, + "NET_WIFI_SECURITY_WEP_64": { + "type": "integer", + "example": 1 + }, + "NET_WIFI_SECURITY_WEP_128": { + "type": "integer", + "example": 2 + }, + "NET_WIFI_SECURITY_WPA_PSK_TKIP": { + "type": "integer", + "example": 3 + }, + "NET_WIFI_SECURITY_WPA_PSK_AES": { + "type": "integer", + "example": 4 + }, + "NET_WIFI_SECURITY_WPA2_PSK_TKIP": { + "type": "integer", + "example": 5 + }, + "NET_WIFI_SECURITY_WPA2_PSK_AES": { + "type": "integer", + "example": 6 + }, + "NET_WIFI_SECURITY_WPA_ENTERPRISE_TKIP": { + "type": "integer", + "example": 7 + }, + "NET_WIFI_SECURITY_WPA_ENTERPRISE_AES": { + "type": "integer", + "example": 8 + }, + "NET_WIFI_SECURITY_WPA2_ENTERPRISE_TKIP": { + "type": "integer", + "example": 9 + }, + "NET_WIFI_SECURITY_WPA2_ENTERPRISE_AES": { + "type": "integer", + "example": 10 + }, + "NET_WIFI_SECURITY_WPA_WPA2_PSK": { + "type": "integer", + "example": 11 + }, + "NET_WIFI_SECURITY_WPA_WPA2_ENTERPRISE": { + "type": "integer", + "example": 12 + }, + "NET_WIFI_SECURITY_WPA3_PSK_AES": { + "type": "integer", + "example": 13 + }, + "NET_WIFI_SECURITY_WPA3_SAE": { + "type": "integer", + "example": 14 + } + }, + "required": [] + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "security_modes", + "success" + ] + } + }, + "SetLogLevel":{ + "summary": "Set Log level for more information. The possible set log level are as follows. \n* `0`: FATAL \n* `1`: ERROR \n* `2`: WARNING \n* `3`: INFO \n* `4`: VERBOSE \n* `5`: TRACE \n", + "params": { + "type": "object", + "properties": { + "loglevel": { + "summary": "Set Log level to get more information", + "type": "integer", + "example": 1 + } + }, + "required": [ + "loglevel" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "EnableInterface":{ + "summary": "Enable the specified interface", + "events":{ + "onInterfaceStateChange" : "Triggered when interface’s status changes to enabled." + }, + "params": { + "type": "object", + "properties": { + "interface": { + "summary": "Enable the specified interface", + "type": "string", + "example": "wlan0" + } + }, + "required": [ + "interface" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "DisableInterface":{ + "summary": "Disable the specified interface", + "events":{ + "onInterfaceStateChange" : "Triggered when interface’s status changes to disabled." + }, + "params": { + "type": "object", + "properties": { + "interface": { + "summary": "Disable the specified interface", + "type": "string", + "example": "wlan0" + } + }, + "required": [ + "interface" + ] + }, + "result": { + "type": "object", + "properties": { + "success": { + "$ref": "#/common/success" + } + }, + "required": [ + "success" + ] + } + }, + "GetWifiState": { + "summary": "Returns the current Wifi State. The possible Wifi states are as follows. \n**Wifi States** \n* `0`: UNINSTALLED - The device was in an installed state and was uninstalled; or, the device does not have a Wifi radio installed \n* `1`: DISABLED - The device is installed but not yet enabled \n* `2`: DISCONNECTED - The device is installed and enabled, but not yet connected to a network \n* `3`: PAIRING - The device is in the process of pairing, but not yet connected to a network \n* `4`: CONNECTING - The device is attempting to connect to a network \n* `5`: CONNECTED - The device is successfully connected to a network \n* `6`: SSID_NOT_FOUND - The requested SSID to connect is not found \n* `7`: SSID_CHANGED - The device connected SSID is changed \n* `8`: CONNECTION_LOST - The device network connection is lost \n* `9`: CONNECTION_FAILED - The device connection got failed \n* `10`: CONNECTION_INTERRUPTED - The device connection is interrupted \n* `11`: INVALID_CREDENTIALS - The credentials provided to connect is not valid \n* `12`: AUTHENTICATION_FAILED - Authentication process as a whole could not be successfully completed \n* `13`: ERROR - The device has encountered an unrecoverable error with the Wifi adapter.", + "result": { + "type": "object", + "properties": { + "state": { + "$ref": "#/definitions/state" + }, + "success":{ + "$ref": "#/common/success" + } + }, + "required": [ + "state", + "success" + ] + } + } + }, + + "events": { + "onInterfaceStateChange":{ + "summary": "Triggered when an interface state is changed. The possible states are \n* 'INTERFACE_ADDED' \n* 'INTERFACE_LINK_UP' \n* 'INTERFACE_LINK_DOWN' \n* 'INTERFACE_ACQUIRING_IP' \n* 'INTERFACE_REMOVED' \n* 'INTERFACE_DISABLED' \n", + "params": { + "type": "object", + "properties": { + "interface":{ + "$ref": "#/definitions/interface" + }, + "state":{ + "summary": "Current state of the interface", + "type": "string", + "example": "INTERFACE_ADDED" + } + }, + "required": [ + "interface", + "state" + ] + } + }, + "onAddressChange":{ + "summary": "Triggered when an IP Address is assigned or lost.", + "params": { + "type": "object", + "properties": { + "interface":{ + "$ref": "#/definitions/interface" + }, + "isIPv6":{ + "summary": "It will be true if the IP address is IPv6", + "type": "boolean", + "example": false + }, + "ipAddress":{ + "summary": "The IPv6 or IPv4 address for the interface", + "type": "string", + "example": "192.168.1.100" + }, + "status":{ + "summary": "Whether IP address was acquired or lost (must be one of the following: 'ACQUIRED', 'LOST')", + "type": "string", + "enum": [ + "`ACQUIRED`", + "`LOST`" + ], + "example": "ACQUIRED" + } + }, + "required": [ + "interface", + "isIPv6", + "ipAddress", + "status" + ] + } + }, + "onActiveInterfaceChange":{ + "summary": "Triggered when the primary/active interface changes, regardless if it's from a system operation or through the `SetPrimaryInterface` method.", + "params": { + "type": "object", + "properties": { + "oldInterfaceName":{ + "summary": "The previous interface that was changed", + "type": "string", + "example": "wlan0" + }, + "newInterfaceName":{ + "summary": "The current interface", + "type": "string", + "example": "eth0" + } + }, + "required": [ + "oldInterfaceName", + "newInterfaceName" + ] + } + }, + "onInternetStatusChange":{ + "summary": "Triggered when internet connection state changed.The possible internet connection status are `NO_INTERNET`, `LIMITED_INTERNET`, `CAPTIVE_PORTAL`, `FULLY_CONNECTED`", + "params": { + "type": "object", + "properties": { + "PrevState":{ + "summary": "The privious internet connection state", + "type": "integer", + "example": 1 + }, + "PrevStatus":{ + "summary": "The previous internet connection status", + "type": "string", + "example": "NO_INTERNET" + }, + "state":{ + "summary": "The internet connection state", + "type": "integer", + "example": 4 + }, + "status":{ + "summary": "The internet connection status", + "type": "string", + "example": "FULLY_CONNECTED" + } + }, + "required": [ + "PrevState", + "PrevStatus", + "state", + "status" + ] + } + }, + "onAvailableSSIDs":{ + "summary": "Triggered when scan completes or when scan cancelled.", + "params": { + "type": "object", + "properties": { + "ssids": { + "summary": "On Available SSID's", + "type":"array", + "items": { + "type":"object", + "properties": { + "ssid":{ + "summary": "ssid", + "type": "string", + "example": "myAP-2.4" + }, + "security":{ + "summary": "security", + "type": "integer", + "example": 6 + }, + "signalStrength":{ + "summary": "signalStrength", + "type": "string", + "example": "-27.000000" + }, + "frequency":{ + "summary": "frequency", + "type": "string", + "example": "2.442000" + } + }, + "required": [ + "ssid", + "security", + "signalStrength", + "frequency" + ] + } + } + } + } + }, + "onWiFiStateChange":{ + "summary": "Triggered when WIFI connection state get changed. The possible states are, \n * '0' - 'WIFI_STATE_UNINSTALLED' \n * '1' - 'WIFI_STATE_DISABLED' \n * '2' - 'WIFI_STATE_DISCONNECTED' \n * '3' - 'WIFI_STATE_PAIRING' \n * '4' - 'WIFI_STATE_CONNECTING' \n * '5' - 'WIFI_STATE_CONNECTED' \n * '6' - 'WIFI_STATE_SSID_NOT_FOUND' \n * '7' - 'WIFI_STATE_SSID_CHANGED' \n * '8' - 'WIFI_STATE_CONNECTION_LOST' \n * '9' - 'WIFI_STATE_CONNECTION_FAILED' \n * '10'- 'WIFI_STATE_CONNECTION_INTERRUPTED' \n * '11' - 'WIFI_STATE_INVALID_CREDENTIALS' \n * '12' - 'WIFI_STATE_AUTHENTICATION_FAILED' \n * '13' - 'WIFI_STATE_ERROR' \n", + "params": { + "type": "object", + "properties": { + "state":{ + "summary": "onWiFiStateChange", + "type": "integer", + "example": "5" + } + }, + "required": [ + "state" + ] + } + }, + "onWiFiSignalStrengthChange":{ + "summary": "Triggered when WIFI connection Signal Strength get changed.", + "params": { + "type": "object", + "properties": { + "ssid":{ + "summary": "Signal Strength changed SSID", + "type": "string", + "example": "home-new_123" + }, + "signalStrength":{ + "summary": "Signal Strength", + "type": "string", + "example": "-27.000000" + }, + "quality":{ + "summary": "Signal quality", + "type": "string", + "example": "Excellent" + } + }, + "required": [ + "ssid", + "signalStrength", + "quality" + ] + } + } + } +} diff --git a/NetworkManager/service/NetworkManagerGnomeProxy.cpp b/NetworkManager/service/NetworkManagerGnomeProxy.cpp new file mode 100755 index 0000000000..046224edf6 --- /dev/null +++ b/NetworkManager/service/NetworkManagerGnomeProxy.cpp @@ -0,0 +1,853 @@ +#include "NetworkManagerImplementation.h" +#include "NetworkManagerGnomeWIFI.h" +#include +#include +#include + +static NMClient *client; + +using namespace WPEFramework; +using namespace WPEFramework::Plugin; +using namespace std; +GMainLoop *g_loop; +static std::vector interfaceList; + +namespace WPEFramework +{ + namespace Plugin + { + wifiManager *wifi = nullptr; + const float signalStrengthThresholdExcellent = -50.0f; + const float signalStrengthThresholdGood = -60.0f; + const float signalStrengthThresholdFair = -67.0f; + NetworkManagerImplementation* _instance = nullptr; + + void NetworkManagerInternalEventHandler(const char *owner, int eventId, void *data, size_t len) + { + return; + } + + void NetworkManagerImplementation::platform_init() + { + ::_instance = this; + GError *error = NULL; + GMainContext *context = g_main_context_new(); + // initialize the NMClient object + client = nm_client_new(NULL, &error); + if (client == NULL) { + NMLOG_TRACE("Error initializing NMClient: %s\n", error->message); + g_error_free(error); + return; + } + g_loop = g_main_loop_new(context, FALSE); + wifi = wifiManager::getInstance(); + return; + } + + uint32_t GetInterfacesName(string &wifiInterface, string ðernetInterface) { + string line; + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + + ifstream file("/etc/device.properties"); + if (!file.is_open()) { + NMLOG_TRACE("Error opening file\n"); + return rc; + } + + while (std::getline(file, line)) { + // Remove newline character if present + if (!line.empty() && line.back() == '\n') { + line.pop_back(); + } + + istringstream iss(line); + string token; + getline(iss, token, '='); + + if (token == "WIFI_INTERFACE") { + std::getline(iss, wifiInterface, '='); + } else if (token == "ETHERNET_INTERFACE") { + std::getline(iss, ethernetInterface, '='); + } + } + + file.close(); + + return rc; + } + + uint32_t NetworkManagerImplementation::GetAvailableInterfaces (Exchange::INetworkManager::IInterfaceDetailsIterator*& interfacesItr/* @out */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + string interfaces[2]; + string wifiInterface; + string ethernetInterface; + NMDeviceType type; + InterfaceDetails tmp; + NMDeviceState state; + NMDevice *device = NULL; + + if(interfaceList.empty()) + { + GetInterfacesName(wifiInterface, ethernetInterface); + interfaces[0] = wifiInterface; + interfaces[1] = ethernetInterface; + for (size_t i = 0; i < 2; i++) { + if(!interfaces[i].empty()) + { + device = nm_client_get_device_by_iface(client, interfaces[i].c_str()); + if (device) + { + if(i == 0) + tmp.m_type = string("WIFI"); + else + tmp.m_type = string("ETHERNET"); + tmp.m_name = interfaces[i].c_str(); + tmp.m_mac = nm_device_get_hw_address(device); + state = nm_device_get_state(device); + tmp.m_isEnabled = (state > NM_DEVICE_STATE_UNAVAILABLE) ? 1 : 0; + tmp.m_isConnected = (state > NM_DEVICE_STATE_DISCONNECTED) ? 1: 0; + interfaceList.push_back(tmp); + g_clear_object(&device); + } + } + } + } + + using Implementation = RPC::IteratorType; + interfacesItr = Core::Service::Create(interfaceList); + rc = Core::ERROR_NONE; + return rc; + } + + /* @brief Get the active Interface used for external world communication */ + uint32_t NetworkManagerImplementation::GetPrimaryInterface (string& interface /* @out */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + GError *error = NULL; + NMActiveConnection *activeConn = NULL; + NMRemoteConnection *remoteConn = NULL; + + activeConn = nm_client_get_primary_connection(client); + if (activeConn == NULL) { + NMLOG_TRACE("Error getting primary connection: %s\n", error->message); + g_error_free(error); + return rc; + } + remoteConn = nm_active_connection_get_connection(activeConn); + + interface = nm_connection_get_interface_name(NM_CONNECTION(remoteConn)); + if(!interface.empty()) + rc = Core::ERROR_NONE; + return rc; + } + + /* @brief Set the active Interface used for external world communication */ + uint32_t NetworkManagerImplementation::SetPrimaryInterface (const string& interface/* @in */) + { + uint32_t rc = Core::ERROR_NONE; + const GPtrArray *connections = nm_client_get_connections(client); + NMConnection *conn = NULL; + NMSettingConnection *settings; + NMRemoteConnection *remoteConnection; + for (guint i = 0; i < connections->len; i++) { + NMConnection *connection = NM_CONNECTION(connections->pdata[i]); + settings = nm_connection_get_setting_connection(connection); + + /* Check if the interface name matches */ + if (g_strcmp0(nm_setting_connection_get_interface_name(settings), interface.c_str()) == 0) { + conn = connection; + break; + } + } + g_object_set(settings, + NM_SETTING_CONNECTION_AUTOCONNECT, + true, + NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, + NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX, + NULL); + const char *uuid = nm_connection_get_uuid(conn); + remoteConnection = nm_client_get_connection_by_uuid(client, uuid); + nm_remote_connection_commit_changes(remoteConnection, false, NULL, NULL); + + return rc; + } + + uint32_t NetworkManagerImplementation::EnableInterface (const string& interface/* @in */) + { + uint32_t rc = Core::ERROR_NONE; + const GPtrArray *devices = nm_client_get_devices(client); + NMDevice *device = NULL; + + for (guint i = 0; i < devices->len; ++i) { + device = NM_DEVICE(g_ptr_array_index(devices, i)); + + // Get the device details + const char *name = nm_device_get_iface(device); + + // Check if the device name matches + if (g_strcmp0(name, interface.c_str()) == 0) { + nm_device_set_managed(device, true); + + NMLOG_TRACE("Interface %s status set to enabled\n", + interface.c_str()); + } + } + + // Cleanup + if(device) + g_clear_object(&device); + return rc; + } + + uint32_t NetworkManagerImplementation::DisableInterface (const string& interface/* @in */) + { + uint32_t rc = Core::ERROR_NONE; + const GPtrArray *devices = nm_client_get_devices(client); + NMDevice *device = NULL; + + for (guint i = 0; i < devices->len; ++i) { + device = NM_DEVICE(g_ptr_array_index(devices, i)); + + // Get the device details + const char *name = nm_device_get_iface(device); + + // Check if the device name matches + if (g_strcmp0(name, interface.c_str()) == 0) { + nm_device_set_managed(device, false); + + NMLOG_TRACE("Interface %s status set to disabled\n", + interface.c_str()); + } + } + + // Cleanup + if(device) + g_clear_object(&device); + return rc; + } + + /* @brief Get IP Address Of the Interface */ + uint32_t NetworkManagerImplementation::GetIPSettings(const string& interface /* @in */, const string& ipversion /* @in */, IPAddressInfo& result /* @out */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + GError *error = NULL; + NMActiveConnection *conn = NULL; + NMIPConfig *ip4_config = NULL; + NMIPConfig *ip6_config = NULL; + const gchar *gateway = NULL; + char **dns_arr = NULL; + NMDhcpConfig *dhcp4_config = NULL; + NMDhcpConfig *dhcp6_config = NULL; + const char* dhcpserver; + NMSettingConnection *settings; + NMIPAddress *address; + + const GPtrArray *connections = nm_client_get_active_connections(client); + + + for (guint i = 0; i < connections->len; i++) { + NMActiveConnection *connection = NM_ACTIVE_CONNECTION(connections->pdata[i]); + settings = nm_connection_get_setting_connection(NM_CONNECTION(nm_active_connection_get_connection(connection))); + + /* Check if the interface name matches */ + if (g_strcmp0(nm_setting_connection_get_interface_name(settings), interface.c_str()) == 0) { + conn = connection; + break; + } + } + if (conn == NULL) { + NMLOG_TRACE("Error getting primary connection: %s\n", error->message); + g_error_free(error); + return rc; + } + + if(0 == strcmp(ipversion.c_str(), "IPv4")) + { + ip4_config = nm_active_connection_get_ip4_config(conn); + if (ip4_config != NULL) { + const GPtrArray *p; + int i; + p = nm_ip_config_get_addresses(ip4_config); + for (i = 0; i < p->len; i++) { + address = static_cast(p->pdata[i]); + } + gateway = nm_ip_config_get_gateway(ip4_config); + } + dns_arr = (char **)nm_ip_config_get_nameservers(ip4_config); + + dhcp4_config = nm_active_connection_get_dhcp4_config(conn); + dhcpserver = nm_dhcp_config_get_one_option (dhcp4_config, + "dhcp_server_identifier"); + + result.m_ipAddrType = ipversion.c_str(); + if(dhcpserver) + result.m_dhcpServer = dhcpserver; + result.m_v6LinkLocal = ""; + result.m_ipAddress = nm_ip_address_get_address(address); + result.m_prefix = nm_ip_address_get_prefix(address); + result.m_gateway = gateway; + if((*(&dns_arr[0]))!=NULL) + result.m_primaryDns = *(&dns_arr[0]); + if((*(&dns_arr[1]))!=NULL ) + result.m_secondaryDns = *(&dns_arr[1]); + + rc = Core::ERROR_NONE; + } + else if(0 == strcmp(ipversion.c_str(), "IPv6")) + { + NMIPAddress *a; + ip6_config = nm_active_connection_get_ip6_config(conn); + if (ip6_config != NULL) { + const GPtrArray *p; + int i; + p = nm_ip_config_get_addresses(ip6_config); + for (i = 0; i < p->len; i++) { + a = static_cast(p->pdata[i]); + result.m_ipAddress = nm_ip_address_get_address(a); + NMLOG_TRACE("\tinet6 %s/%d\n", nm_ip_address_get_address(a), nm_ip_address_get_prefix(a)); + } + gateway = nm_ip_config_get_gateway(ip6_config); + + dns_arr = (char **)nm_ip_config_get_nameservers(ip6_config); + + dhcp6_config = nm_active_connection_get_dhcp6_config(conn); + dhcpserver = nm_dhcp_config_get_one_option (dhcp6_config, + "dhcp_server_identifier"); + result.m_ipAddrType = ipversion.c_str(); + if(dhcpserver) + result.m_dhcpServer = dhcpserver; + result.m_v6LinkLocal = ""; + result.m_prefix = 0; + result.m_gateway = gateway; + if((*(&dns_arr[0]))!=NULL) + result.m_primaryDns = *(&dns_arr[0]); + if((*(&dns_arr[1]))!=NULL ) + result.m_secondaryDns = *(&dns_arr[1]); + } + rc = Core::ERROR_NONE; + } + return rc; + } + + + // Callback for nm_client_deactivate_connection_async + static void on_deactivate_complete(GObject *source_object, GAsyncResult *res, gpointer user_data) { + GError *error = NULL; + + // Check if the operation was successful + if (!nm_client_deactivate_connection_finish(NM_CLIENT(source_object), res, &error)) { + NMLOG_TRACE("Deactivating connection failed: %s\n", error->message); + g_error_free(error); + } else { + NMLOG_TRACE("Deactivating connection successful\n"); + } + } + + // Callback for nm_client_activate_connection_async + static void on_activate_complete(GObject *source_object, GAsyncResult *res, gpointer user_data) { + GError *error = NULL; + + // Check if the operation was successful + if (!nm_client_activate_connection_finish(NM_CLIENT(source_object), res, &error)) { + NMLOG_TRACE("Activating connection failed: %s\n", error->message); + g_error_free(error); + } else { + NMLOG_TRACE("Activating connection successful\n"); + } + + g_main_loop_quit((GMainLoop*)user_data); + } + + + /* @brief Set IP Address Of the Interface */ + uint32_t NetworkManagerImplementation::SetIPSettings(const string& interface /* @in */, const string &ipversion /* @in */, const IPAddressInfo& address /* @in */) + { + uint32_t rc = Core::ERROR_NONE; + const GPtrArray *connections = nm_client_get_connections(client); + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + NMConnection *conn = NULL; + NMSettingConnection *settings; + NMRemoteConnection *remote_connection; + NMSetting *setting; + const char *uuid; + NMDevice *device = NULL; + const char *spec_object; + + for (guint i = 0; i < connections->len; i++) { + NMConnection *connection = NM_CONNECTION(connections->pdata[i]); + settings = nm_connection_get_setting_connection(connection); + + /* Check if the interface name matches */ + if (g_strcmp0(nm_setting_connection_get_interface_name(settings), interface.c_str()) == 0) { + conn = connection; + break; + } + } + if (!address.m_autoConfig) + { + if (strcasecmp("IPv4", ipversion.c_str()) == 0) + { + NMSettingIPConfig *ip4_config = nm_connection_get_setting_ip4_config(conn); + if (ip4_config == NULL) + { + ip4_config = (NMSettingIPConfig *)nm_setting_ip4_config_new(); + } + NMIPAddress *ipAddress; + setting = nm_connection_get_setting_by_name(conn, "ipv4"); + ipAddress = nm_ip_address_new(AF_INET, address.m_ipAddress.c_str(), address.m_prefix, NULL); + nm_setting_ip_config_clear_addresses(ip4_config); + nm_setting_ip_config_add_address(NM_SETTING_IP_CONFIG(setting), ipAddress); + nm_setting_ip_config_clear_dns(ip4_config); + nm_setting_ip_config_add_dns(ip4_config, address.m_primaryDns.c_str()); + nm_setting_ip_config_add_dns(ip4_config, address.m_secondaryDns.c_str()); + + g_object_set(G_OBJECT(ip4_config), + NM_SETTING_IP_CONFIG_GATEWAY, address.m_gateway.c_str(), + NM_SETTING_IP_CONFIG_NEVER_DEFAULT, + FALSE, + NULL); + } + else + { + //FIXME : Add IPv6 support here + printf("Setting IPv6 is not supported at this point in time. This is just a place holder\n"); + rc = Core::ERROR_NOT_SUPPORTED; + } + } + else + { + if (strcmp("IPv4", ipversion.c_str()) == 0) + { + s_ip4 = (NMSettingIP4Config *)nm_setting_ip4_config_new(); + g_object_set(G_OBJECT(s_ip4), NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting(conn, NM_SETTING(s_ip4)); + } + else + { + s_ip6 = (NMSettingIP6Config *)nm_setting_ip6_config_new(); + g_object_set(G_OBJECT(s_ip6), NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting(conn, NM_SETTING(s_ip6)); + } + } + device = nm_client_get_device_by_iface(client, interface.c_str()); + uuid = nm_connection_get_uuid(conn); + remote_connection = nm_client_get_connection_by_uuid(client, uuid); + NMActiveConnection *active_connection = NULL; + + const GPtrArray *acv_connections = nm_client_get_active_connections(client); + for (guint i = 0; i < acv_connections->len; i++) { + NMActiveConnection *connection1 = NM_ACTIVE_CONNECTION(acv_connections->pdata[i]); + settings = nm_connection_get_setting_connection(NM_CONNECTION(nm_active_connection_get_connection(connection1))); + + /* Check if the interface name matches */ + if (g_strcmp0(nm_setting_connection_get_interface_name(settings), interface.c_str()) == 0) { + active_connection = connection1; + break; + } + } + + spec_object = nm_object_get_path(NM_OBJECT(active_connection)); + nm_remote_connection_commit_changes(remote_connection, false, NULL, NULL); + nm_client_deactivate_connection_async(client, active_connection, NULL, on_deactivate_complete, NULL); + nm_client_activate_connection_async(client, conn, device, spec_object, NULL, on_activate_complete, g_loop); + g_main_loop_run(g_loop); + return rc; + } + + static void on_scan_done(GObject *source_object, GAsyncResult *result, gpointer user_data) + { + GError *error = NULL; + GBytes *ssid = NULL; + NMAccessPoint *ap = NULL; + int strength = 0; + std::string freq; + guint security; + guint32 flags, wpaFlags, rsnFlags, ap_freq; + JsonArray ssidList = JsonArray(); + JsonObject ssidObj; + gboolean success = nm_device_wifi_request_scan_finish(NM_DEVICE_WIFI(source_object), result, &error); + if (success) + { + NMDeviceWifi *wifi_device = NM_DEVICE_WIFI(source_object); + const GPtrArray *access_points = nm_device_wifi_get_access_points(wifi_device); + NMLOG_INFO("Number of Access Points Scanned=%d\n",access_points->len); + for (guint i = 0; i < access_points->len; i++) + { + char* ssid_str = NULL; + ap = (NMAccessPoint*)access_points->pdata[i]; + ssid = nm_access_point_get_ssid(ap); + if (ssid) + { + ssid_str = nm_utils_ssid_to_utf8((const guint8*)g_bytes_get_data(ssid, NULL), g_bytes_get_size(ssid)); + strength = nm_access_point_get_strength(ap); + ap_freq = nm_access_point_get_frequency(ap); + flags = nm_access_point_get_flags(ap); + wpaFlags = nm_access_point_get_wpa_flags(ap); + rsnFlags = nm_access_point_get_rsn_flags(ap); + if (ap_freq >= 2400 && ap_freq < 5000) { + freq = "2.4"; + } + else if (ap_freq >= 5000 && ap_freq < 6000) { + freq = "5"; + } + else if (ap_freq >= 6000) { + freq = "6"; + } + else { + freq = "Not available"; + } + if ((flags == NM_802_11_AP_FLAGS_NONE) && (wpaFlags == NM_802_11_AP_SEC_NONE) && (rsnFlags == NM_802_11_AP_SEC_NONE)) + { + security = 0; + } + else if( (flags & NM_802_11_AP_FLAGS_PRIVACY) && ((wpaFlags & NM_802_11_AP_SEC_PAIR_WEP40) || (rsnFlags & NM_802_11_AP_SEC_PAIR_WEP40)) ) + { + security = 1; + } + else if( (flags & NM_802_11_AP_FLAGS_PRIVACY) && ((wpaFlags & NM_802_11_AP_SEC_PAIR_WEP104) || (rsnFlags & NM_802_11_AP_SEC_PAIR_WEP104)) ) + { + security = 2; + } + else if((wpaFlags & NM_802_11_AP_SEC_PAIR_TKIP) || (rsnFlags & NM_802_11_AP_SEC_PAIR_TKIP)) + { + security = 3; + } + else if((wpaFlags & NM_802_11_AP_SEC_PAIR_CCMP) || (rsnFlags & NM_802_11_AP_SEC_PAIR_CCMP)) + { + security = 4; + } + else if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) && (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) + { + security = 12; + } + else if(rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + { + security = 11; + } + else if((wpaFlags & NM_802_11_AP_SEC_GROUP_CCMP) || (rsnFlags & NM_802_11_AP_SEC_GROUP_CCMP)) + { + security = 6; + } + else if((wpaFlags & NM_802_11_AP_SEC_GROUP_TKIP) || (rsnFlags & NM_802_11_AP_SEC_GROUP_TKIP)) + { + security = 5;; + } + else + { + NMLOG_WARNING("security mode not defined"); + } + } + if(ssid_str) + { + string ssidString(ssid_str); + ssidObj["ssid"] = ssidString; + ssidObj["security"] = security; + ssidObj["signalStrength"] = strength; + ssidObj["frequency"] = freq; + ssidList.Add(ssidObj); + } + } + } + else + { + NMLOG_ERROR("Error requesting Wi-Fi scan: %s\n", error->message); + } + string json; + ssidList.ToString(json); + NMLOG_INFO("Scanned APIs are = %s",json.c_str()); + ::_instance->ReportAvailableSSIDsEvent(json); + g_main_loop_quit((GMainLoop *)user_data); + } + + uint32_t NetworkManagerImplementation::StartWiFiScan(const WiFiFrequency frequency /* @in */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + GMainLoop *loop; + loop = g_main_loop_new(NULL, FALSE); + NMDevice *wifi_device; + wifi_device = nm_client_get_device_by_iface(client, "wlan0"); + nm_device_wifi_request_scan_options_async(NM_DEVICE_WIFI(wifi_device), NULL, NULL, on_scan_done, loop);//TODO Explore further on the API and check whether w which all options can be passed as Argument. Example : We can pass SSID as an option and scan for that SSID alone + g_main_loop_run(loop); + rc = Core::ERROR_NONE; + return rc; + } + + uint32_t NetworkManagerImplementation::StopWiFiScan(void) + { + uint32_t rc = Core::ERROR_NONE; + //TODO + //Explore nm_device_wifi_request_scan_finish and other API which can be used stop scan + NMLOG_INFO ("StopWiFiScan is success\n"); + return rc; + } + + uint32_t NetworkManagerImplementation::GetKnownSSIDs(IStringIterator*& ssids /* @out */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + NMClient *g_cli = nm_client_new(NULL, NULL); + const GPtrArray *connections = nm_client_get_connections(g_cli); + std::list ssidList; + for (guint i = 0; i < connections->len; i++) + { + NMConnection *connection = NM_CONNECTION(connections->pdata[i]); + + if (NM_IS_SETTING_WIRELESS(nm_connection_get_setting_wireless(connection))) + { + GBytes *ssid_bytes = nm_setting_wireless_get_ssid(nm_connection_get_setting_wireless(connection)); + if (ssid_bytes) + { + gsize ssid_size; + const char *ssid = (const char*)g_bytes_get_data(ssid_bytes, &ssid_size); + if (ssid) + { + ssidList.push_back(ssid); + rc = Core::ERROR_NONE; + } + } + } + } + if (!ssidList.empty()) + { + NMLOG_INFO ("GetKnownSSIDs success\n"); + ssids = Core::Service::Create(ssidList); + } + return rc; + } + + static void add_callback(GObject *s, GAsyncResult *result, gpointer user_data) + { + + GError *error = NULL; + NMRemoteConnection *connection = NM_REMOTE_CONNECTION(s); + + if (!nm_remote_connection_delete_finish(connection, result, &error)) { + NMLOG_ERROR ("AddToKnownSSIDs Failed\n"); + } + else + { + NMLOG_INFO ("AddToKnownSSIDs is success\n"); + } + + g_object_unref(connection); + g_main_loop_quit((GMainLoop *)user_data); + + } + + uint32_t NetworkManagerImplementation::AddToKnownSSIDs(const WiFiConnectTo& ssid /* @in */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + GMainLoop *loop; + loop = g_main_loop_new(NULL, FALSE); + NMClient *g_cli = nm_client_new(NULL, NULL); + NMSettingWirelessSecurity *s_secure; + NMSettingWireless *s_wireless; + const char *uuid = nm_utils_uuid_generate(); + s_secure = (NMSettingWirelessSecurity *)nm_setting_wireless_security_new(); + NMSettingConnection *s_con = (NMSettingConnection *)nm_setting_connection_new(); + g_object_set(G_OBJECT(s_con), + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_ID, + ssid.m_ssid.c_str(), + NM_SETTING_CONNECTION_TYPE, + "802-11-wireless", + NULL); + NMConnection *connection = nm_simple_connection_new(); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + s_wireless = (NMSettingWireless *)nm_setting_wireless_new(); + GString *ssid_str = g_string_new(ssid.m_ssid.c_str()); + g_object_set(G_OBJECT(s_wireless), + NM_SETTING_WIRELESS_SSID, + ssid_str, + NULL); + nm_connection_add_setting(connection, NM_SETTING(s_wireless)); + s_secure = (NMSettingWirelessSecurity *)nm_setting_wireless_security_new(); + switch(ssid.m_securityMode) + { + case WIFI_SECURITY_WPA_PSK_AES: + { + g_object_set(G_OBJECT(s_secure), + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_PSK, + ssid.m_passphrase.c_str(), + NULL); + + break; + } + case WIFI_SECURITY_WPA2_PSK_AES: + { + g_object_set(G_OBJECT(s_secure), + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_PSK, + ssid.m_passphrase.c_str(), + NULL); + break; + } + default: + { + g_object_set(G_OBJECT(s_secure), + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_PSK, + ssid.m_passphrase.c_str(), + NULL); + break; + } + } + nm_connection_add_setting(connection, NM_SETTING(s_secure)); + nm_client_add_connection_async(g_cli, connection, NULL, NULL, add_callback, loop); + rc = Core::ERROR_NONE; + g_main_loop_unref(loop); + + return rc; + } + + uint32_t NetworkManagerImplementation::RemoveKnownSSID(const string& ssid /* @in */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + NMRemoteConnection* remoteConnection; + NMClient *g_cli = nm_client_new(NULL, NULL); + const GPtrArray* connections = nm_client_get_connections(g_cli); + for (guint i = 0; i < connections->len; i++) + { + remoteConnection = NM_REMOTE_CONNECTION(connections->pdata[i]); + NMConnection *connection = NM_CONNECTION(connections->pdata[i]); + if (NM_IS_SETTING_WIRELESS(nm_connection_get_setting_wireless(connection))) + { + GBytes *ssid_bytes = nm_setting_wireless_get_ssid(nm_connection_get_setting_wireless(connection)); + if (ssid_bytes) + { + gsize ssid_size; + const char *ssid_str = (const char*)g_bytes_get_data(ssid_bytes, &ssid_size); + if (ssid == ssid_str) + { + GError *error = NULL; + nm_remote_connection_delete(remoteConnection, NULL, &error); + if (error) + { + NMLOG_ERROR("RemoveKnownSSID failed\n"); + g_error_free(error); + } + else + { + NMLOG_INFO("RemoveKnownSSID is success\n"); + rc = Core::ERROR_NONE; + } + break; + } + } + } + } + return rc; + } + + uint32_t NetworkManagerImplementation::WiFiConnect(const WiFiConnectTo& ssid /* @in */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + if(wifi->wifiConnect(ssid.m_ssid.c_str(), ssid.m_passphrase.c_str(), ssid.m_securityMode)) + rc = Core::ERROR_NONE; + return rc; + } + + uint32_t NetworkManagerImplementation::WiFiDisconnect(void) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + if(wifi->wifiDisconnect()) + rc = Core::ERROR_NONE; + return rc; + } + + uint32_t NetworkManagerImplementation::GetConnectedSSID(WiFiSSIDInfo& ssidInfo /* @out */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + if(wifi->wifiConnectedSSIDInfo(ssidInfo)) + rc = Core::ERROR_NONE; + return rc; + } + + uint32_t NetworkManagerImplementation::GetWiFiSignalStrength(string& ssid /* @out */, string& signalStrength /* @out */, WiFiSignalQuality& quality /* @out */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + float signalStrengthOut = 0.0f; + NMClient *g_cli = nm_client_new(NULL, NULL); + + const GPtrArray *devices = nm_client_get_devices(g_cli); + + /* Go through the device array and process Wi-Fi devices */ + for (guint i = 0; i < devices->len; i++) + { + NMDevice *device = (NMDevice *)g_ptr_array_index(devices, i); + if (NM_IS_DEVICE_WIFI(device)) + { + NMAccessPoint *active_ap = NULL; + GBytes *active_ssid; + char *active_ssid_str = NULL; + + /* Get active AP */ + if (nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) + { + if ((active_ap = nm_device_wifi_get_active_access_point(NM_DEVICE_WIFI(device)))) + { + active_ssid = nm_access_point_get_ssid(active_ap); + if (active_ssid) + { + active_ssid_str = nm_utils_ssid_to_utf8(static_cast(g_bytes_get_data(active_ssid, NULL)), g_bytes_get_size(active_ssid)); + ssid = active_ssid_str; + } + + char *strength_str; + guint8 strength; + strength = nm_access_point_get_strength(active_ap); + strength_str = g_strdup_printf("%u", strength); + signalStrength = strength_str; + g_free(strength_str); + if(!signalStrength.empty()) + signalStrengthOut = std::stof(signalStrength.c_str()); + + if (signalStrengthOut == 0) + quality = WIFI_SIGNAL_DISCONNECTED; + else if (signalStrengthOut >= signalStrengthThresholdExcellent && signalStrengthOut < 0) + quality = WIFI_SIGNAL_EXCELLENT; + else if (signalStrengthOut >= signalStrengthThresholdGood && signalStrengthOut < signalStrengthThresholdExcellent) + quality = WIFI_SIGNAL_GOOD; + else if (signalStrengthOut >= signalStrengthThresholdFair && signalStrengthOut < signalStrengthThresholdGood) + quality = WIFI_SIGNAL_FAIR; + else + quality = WIFI_SIGNAL_WEAK; + + NMLOG_INFO ("GetWiFiSignalStrength success\n"); + g_free(active_ssid_str); + rc = Core::ERROR_NONE; + break; + } + } + } + } + return rc; + } + + uint32_t NetworkManagerImplementation::StartWPS(const WiFiWPS& method /* @in */, const string& wps_pin /* @in */) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + return rc; + } + + uint32_t NetworkManagerImplementation::StopWPS(void) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + return rc; + } + + uint32_t NetworkManagerImplementation::GetWifiState(WiFiState &state) + { + uint32_t rc = Core::ERROR_NONE; + + state = Exchange::INetworkManager::WIFI_STATE_CONNECTED; + return rc; + } + } +} diff --git a/NetworkManager/service/NetworkManagerGnomeWIFI.cpp b/NetworkManager/service/NetworkManagerGnomeWIFI.cpp new file mode 100644 index 0000000000..a52d9e4b8c --- /dev/null +++ b/NetworkManager/service/NetworkManagerGnomeWIFI.cpp @@ -0,0 +1,727 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * 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 +#include +#include +#include + +#include +#include +#include +#include "NetworkManagerLogger.h" +#include "INetworkManager.h" +#include "NetworkManagerGnomeWIFI.h" + +namespace WPEFramework +{ + namespace Plugin + { + NMDevice* wifiManager::getNmDevice() + { + NMDevice *wifiDevice = NULL; + + GPtrArray *devices = const_cast(nm_client_get_devices(client)); + if (devices == NULL) { + NMLOG_ERROR("Failed to get device list."); + return wifiDevice; + } + + for (guint j = 0; j < devices->len; j++) { + NMDevice *device = NM_DEVICE(devices->pdata[j]); + if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_WIFI) + { + wifiDevice = device; + //NMLOG_TRACE("Wireless Device found ifce : %s !", nm_device_get_iface (wifiDevice)); + break; + } + } + + if (wifiDevice == NULL || !NM_IS_DEVICE_WIFI(wifiDevice)) + { + NMLOG_ERROR("Wireless Device not found !"); + } + + return wifiDevice; + } + + /* Convert flags to string */ + static void apFlagsToString(guint32 flags, std::string &flagStr) + { + + flagStr = ""; + + if (flags & NM_802_11_AP_SEC_PAIR_WEP40) + flagStr += "pair_wpe40 "; + if (flags & NM_802_11_AP_SEC_PAIR_WEP104) + flagStr += "pair_wpe104 "; + if (flags & NM_802_11_AP_SEC_PAIR_TKIP) + flagStr += "pair_tkip "; + if (flags & NM_802_11_AP_SEC_PAIR_CCMP) + flagStr += "pair_ccmp "; + if (flags & NM_802_11_AP_SEC_GROUP_WEP40) + flagStr += "group_wpe40 "; + if (flags & NM_802_11_AP_SEC_GROUP_WEP104) + flagStr += "group_wpe104 "; + if (flags & NM_802_11_AP_SEC_GROUP_TKIP) + flagStr += "group_tkip "; + if (flags & NM_802_11_AP_SEC_GROUP_CCMP) + flagStr += "group_ccmp "; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + flagStr += "psk "; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + flagStr += "802.1X "; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) + flagStr += "sae "; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_OWE) + flagStr += "owe " ; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_OWE_TM) + flagStr += "owe_transition_mode "; + if (flags & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192) + flagStr += "wpa-eap-suite-b-192 "; + + if (flagStr.size() <= 0) + flagStr = "none"; + } + + bool static getConnectedSSID(NMDeviceWifi *wifiDevice, std::string& ssidin) + { + GBytes *ssid; + NMAccessPoint *activeAP = nm_device_wifi_get_active_access_point(wifiDevice); + if(activeAP == NULL) { + return false; + } + + ssid = nm_access_point_get_ssid(activeAP); + gsize size; + const guint8 *ssidData = static_cast(g_bytes_get_data(ssid, &size)); + std::string ssidTmp(reinterpret_cast(ssidData), size); + ssidin = ssidTmp; + NMLOG_INFO("connected ssid: %s", ssidin.c_str()); + return true; + } + + static void getApInfo(NMAccessPoint *AccessPoint, Exchange::INetworkManager::WiFiSSIDInfo &wifiInfo) + { + guint32 flags, wpaFlags, rsnFlags, freq, bitrate; + guint8 strength; + GBytes *ssid; + const char *hwaddr; + NM80211Mode mode; + /* Get AP properties */ + flags = nm_access_point_get_flags(AccessPoint); + wpaFlags = nm_access_point_get_wpa_flags(AccessPoint); + rsnFlags = nm_access_point_get_rsn_flags(AccessPoint); + ssid = nm_access_point_get_ssid(AccessPoint); + hwaddr = nm_access_point_get_bssid(AccessPoint); + freq = nm_access_point_get_frequency(AccessPoint); + mode = nm_access_point_get_mode(AccessPoint); + bitrate = nm_access_point_get_max_bitrate(AccessPoint); + strength = nm_access_point_get_strength(AccessPoint); + + switch(flags) + { + case NM_802_11_AP_FLAGS_NONE: + NMLOG_INFO("ap type : point has no special capabilities"); + break; + case NM_802_11_AP_FLAGS_PRIVACY: + NMLOG_INFO("ap type : access point requires authentication and encryption"); + break; + case NM_802_11_AP_FLAGS_WPS: + NMLOG_INFO("ap type : access point supports some WPS method"); + break; + case NM_802_11_AP_FLAGS_WPS_PBC: + NMLOG_INFO("ap type : access point supports push-button WPS"); + break; + case NM_802_11_AP_FLAGS_WPS_PIN: + NMLOG_INFO("ap type : access point supports PIN-based WPS"); + break; + default: + NMLOG_ERROR("ap type : 802.11 flags unknown!"); + } + + /* Convert to strings */ + if (ssid) { + gsize size; + const guint8 *ssidData = static_cast(g_bytes_get_data(ssid, &size)); + std::string ssidTmp(reinterpret_cast(ssidData), size); + wifiInfo.m_ssid = ssidTmp; + NMLOG_INFO("ssid: %s", wifiInfo.m_ssid.c_str()); + } + else + { + wifiInfo.m_ssid = "-----"; + NMLOG_TRACE("ssid: %s", wifiInfo.m_ssid.c_str()); + } + + wifiInfo.m_bssid = (hwaddr != nullptr) ? hwaddr : "-----"; + NMLOG_INFO("bssid: %s", wifiInfo.m_bssid.c_str()); + + + if (freq >= 2400 && freq < 5000) { + wifiInfo.m_frequency = Exchange::INetworkManager::WiFiFrequency::WIFI_FREQUENCY_2_4_GHZ; + NMLOG_INFO("freq: WIFI_FREQUENCY_2_4_GHZ"); + } + else if (freq >= 5000 && freq < 6000) { + wifiInfo.m_frequency = Exchange::INetworkManager::WiFiFrequency::WIFI_FREQUENCY_5_GHZ; + NMLOG_INFO("freq: WIFI_FREQUENCY_5_GHZ"); + } + else if (freq >= 6000) { + wifiInfo.m_frequency = Exchange::INetworkManager::WiFiFrequency::WIFI_FREQUENCY_6_GHZ; + NMLOG_INFO("freq: WIFI_FREQUENCY_6_GHZ"); + } + else { + wifiInfo.m_frequency = Exchange::INetworkManager::WiFiFrequency::WIFI_FREQUENCY_WHATEVER; + NMLOG_INFO("freq: No available !"); + } + + wifiInfo.m_rate = std::to_string(bitrate); + NMLOG_INFO("bitrate : %s kbit/s", wifiInfo.m_rate.c_str()); + + wifiInfo.m_signalStrength = std::to_string(static_cast(strength)); + NMLOG_INFO("sterngth: %s %%", wifiInfo.m_signalStrength.c_str()); + //TODO signal strenght to dBm + + std::string security_str = ""; + if ((flags == NM_802_11_AP_FLAGS_NONE) && (wpaFlags == NM_802_11_AP_SEC_NONE) && (rsnFlags == NM_802_11_AP_SEC_NONE)) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_NONE; + } + else if( (flags & NM_802_11_AP_FLAGS_PRIVACY) && ((wpaFlags & NM_802_11_AP_SEC_PAIR_WEP40) || (rsnFlags & NM_802_11_AP_SEC_PAIR_WEP40)) ) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WEP_64; + } + else if( (flags & NM_802_11_AP_FLAGS_PRIVACY) && ((wpaFlags & NM_802_11_AP_SEC_PAIR_WEP104) || (rsnFlags & NM_802_11_AP_SEC_PAIR_WEP104)) ) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WEP_128; + } + else if((wpaFlags & NM_802_11_AP_SEC_PAIR_TKIP) || (rsnFlags & NM_802_11_AP_SEC_PAIR_TKIP)) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WPA_PSK_TKIP; + } + else if((wpaFlags & NM_802_11_AP_SEC_PAIR_CCMP) || (rsnFlags & NM_802_11_AP_SEC_PAIR_CCMP)) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WPA_PSK_AES; + } + else if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) && (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WPA_WPA2_ENTERPRISE; + } + else if(rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WPA_WPA2_PSK; + } + else if((wpaFlags & NM_802_11_AP_SEC_GROUP_CCMP) || (rsnFlags & NM_802_11_AP_SEC_GROUP_CCMP)) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WPA2_PSK_AES; + } + else if((wpaFlags & NM_802_11_AP_SEC_GROUP_TKIP) || (rsnFlags & NM_802_11_AP_SEC_GROUP_TKIP)) + { + wifiInfo.m_securityMode = Exchange::INetworkManager::WIFISecurityMode::WIFI_SECURITY_WPA2_PSK_TKIP; + } + else + { + NMLOG_WARNING("security mode not defined"); + } + + if (!(flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpaFlags != NM_802_11_AP_SEC_NONE) && (rsnFlags != NM_802_11_AP_SEC_NONE)) + security_str += ("Encrypted: "); + + if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpaFlags == NM_802_11_AP_SEC_NONE) + && (rsnFlags == NM_802_11_AP_SEC_NONE)) + security_str += ("WEP "); + if (wpaFlags != NM_802_11_AP_SEC_NONE) + security_str += ("WPA "); + if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + security_str += ("WPA2 "); + } + if (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { + security_str += ("WPA3 "); + } + if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE) + || (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { + security_str += ("OWE "); + } + if ((wpaFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + || (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + security_str += ("802.1X "); + } + + NMLOG_INFO("security: %s", (security_str.size() > 0)? security_str.c_str(): "none"); + std::string flagStr; + apFlagsToString(wpaFlags, flagStr); + apFlagsToString(rsnFlags, flagStr); + NMLOG_INFO("WPA flags: %s", flagStr.c_str()); + NMLOG_INFO("RSN flags: %s", flagStr.c_str()); + NMLOG_TRACE("D-Bus path: %s", nm_object_get_path(NM_OBJECT(AccessPoint))); + NMLOG_INFO("Mode: %s", mode == NM_802_11_MODE_ADHOC ? "Ad-Hoc": mode == NM_802_11_MODE_INFRA ? "Infrastructure": "Unknown"); + } + + bool wifiManager::isWifiConnected() + { + if(!createClientNewConnection()) + return false; + + NMDeviceWifi *wifiDevice = NM_DEVICE_WIFI(getNmDevice()); + if(wifiDevice == NULL) { + NMLOG_TRACE("NMDeviceWifi * NULL !"); + return false; + } + + NMAccessPoint *activeAP = nm_device_wifi_get_active_access_point(wifiDevice); + if(activeAP == NULL) { + NMLOG_ERROR("No active access point found !"); + return false; + } + else + NMLOG_TRACE("active access point found !"); + return true; + } + + bool wifiManager::wifiConnectedSSIDInfo(Exchange::INetworkManager::WiFiSSIDInfo &ssidinfo) + { + if(!createClientNewConnection()) + return false; + + NMDeviceWifi *wifiDevice = NM_DEVICE_WIFI(getNmDevice()); + if(wifiDevice == NULL) { + NMLOG_TRACE("NMDeviceWifi * NULL !"); + return false; + } + + NMAccessPoint *activeAP = nm_device_wifi_get_active_access_point(wifiDevice); + if(activeAP == NULL) { + NMLOG_ERROR("No active access point found !"); + return false; + } + else + NMLOG_TRACE("active access point found !"); + + getApInfo(activeAP, ssidinfo); + return true; + } + + static void wifiDisconnectCb(GObject *object, GAsyncResult *result, gpointer user_data) + { + NMDevice *device = NM_DEVICE(object); + GError *error = NULL; + wifiManager *_wifiManager = (static_cast(user_data)); + + NMLOG_TRACE("Disconnecting... "); + if (!nm_device_disconnect_finish(device, result, &error)) { + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + NMLOG_ERROR("Device '%s' (%s) disconnecting failed: %s", + nm_device_get_iface(device), + nm_object_get_path(NM_OBJECT(device)), + error->message); + g_error_free(error); + _wifiManager->quit(device); + } + } + + void static disconnectGsignalCb(NMDevice *device, GParamSpec *pspec, wifiManager *info) + { + if(NM_IS_DEVICE_WIFI(device)) + { + NMDeviceState state = nm_device_get_state(device); + switch(state) + { + case NM_DEVICE_STATE_DEACTIVATING: + NMLOG_INFO("Device '%s' successfully disconnecting", nm_device_get_iface(device)); + break; + case NM_DEVICE_STATE_DISCONNECTED: + NMLOG_INFO("Device '%s' successfully disconnected", nm_device_get_iface(device)); + info->quit(device); + break; + case NM_DEVICE_STATE_ACTIVATED: + NMLOG_INFO("Device '%s' successfully connected", nm_device_get_iface(device)); + info->quit(device); + case NM_DEVICE_STATE_FAILED: + NMLOG_INFO("Device '%s' Failed state", nm_device_get_iface(device)); + break; + default: + NMLOG_TRACE("Device state unknown"); + } + } + } + + static void connectGsignalCb(NMDevice *device, GParamSpec *pspec, wifiManager *info) + { + if(NM_IS_DEVICE_WIFI(device)) + { + NMDeviceState state = nm_device_get_state(device); + switch(state) + { + case NM_DEVICE_STATE_DEACTIVATING: + NMLOG_INFO("Device disconnecting"); + break; + case NM_DEVICE_STATE_DISCONNECTED: + NMLOG_INFO("Device '%s' successfully disconnected", nm_device_get_iface(device)); + break; + case NM_DEVICE_STATE_ACTIVATED: + NMLOG_INFO("Device '%s' successfully connected", nm_device_get_iface(device)); + info->quit(device); + case NM_DEVICE_STATE_FAILED: + //NMLOG_INFO("Device '%s' Failed state", nm_device_get_iface(device)); + default: + break; + } + } + } + + bool wifiManager::wifiDisconnect() + { + if(!createClientNewConnection()) + return false; + + NMDevice *wifiNMDevice = getNmDevice(); + if(wifiNMDevice == NULL) { + NMLOG_TRACE("NMDeviceWifi NULL !"); + return false; + } + + wifiDeviceStateGsignal = g_signal_connect(wifiNMDevice, "notify::" NM_DEVICE_STATE, G_CALLBACK(disconnectGsignalCb), this); + nm_device_disconnect_async(wifiNMDevice, NULL, wifiDisconnectCb, this); + wait(loop); + NMLOG_TRACE("Exit"); + return true; + } + + bool wifiManager::quit(NMDevice *wifiNMDevice) + { + if (wifiNMDevice && wifiDeviceStateGsignal > 0) { + g_signal_handler_disconnect(wifiNMDevice, wifiDeviceStateGsignal); + wifiDeviceStateGsignal = 0; + } + + if(!g_main_loop_is_running(loop)) { + NMLOG_ERROR("g_main_loop_is not running"); + return false; + } + + g_main_loop_quit(loop); + return false; + } + + bool wifiManager::wait(GMainLoop *loop) + { + if(g_main_loop_is_running(loop)) { + NMLOG_WARNING("g_main_loop_is running"); + return false; + } + g_main_loop_run(loop); + return true; + } + + static NMAccessPoint *checkSSIDAvailable(NMDevice *device, const GPtrArray *aps, const char *ssid) + { + NMAccessPoint *AccessPoint = NULL; + aps = nm_device_wifi_get_access_points(NM_DEVICE_WIFI(device)); + for (guint i = 0; i < aps->len; i++) + { + NMAccessPoint *candidate_ap = static_cast(g_ptr_array_index(aps, i)); + if (ssid) + { + GBytes *ssidGBytes; + ssidGBytes = nm_access_point_get_ssid(candidate_ap); + if (!ssidGBytes) + continue; + gsize size; + const guint8 *ssidData = static_cast(g_bytes_get_data(ssidGBytes, &size)); + std::string ssidstr(reinterpret_cast(ssidData), size); + //g_bytes_unref(ssidGBytes); + NMLOG_TRACE("ssid < %s >", ssidstr.c_str()); + if (strcmp(ssid, ssidstr.c_str()) == 0) + { + AccessPoint = candidate_ap; + break; + } + } + } + + return AccessPoint; + } + + static void wifiConnectCb(GObject *client, GAsyncResult *result, gpointer user_data) + { + GError *error = NULL; + wifiManager *_wifiManager = (static_cast(user_data)); + + if (_wifiManager->createNewConnection) { + NMLOG_TRACE("nm_client_add_and_activate_connection_finish"); + nm_client_add_and_activate_connection_finish(NM_CLIENT(_wifiManager->client), result, &error); + } + else { + NMLOG_TRACE("nm_client_activate_connection_finish "); + nm_client_activate_connection_finish(NM_CLIENT(_wifiManager->client), result, &error); + } + + if (error) { + if (_wifiManager->createNewConnection) { + NMLOG_ERROR("Failed to add/activate new connection: %s", error->message); + } else { + NMLOG_ERROR("Failed to activate connection: %s", error->message); + } + g_main_loop_quit(_wifiManager->loop); + } + } + + static void wifiConnectionUpdate(GObject *source_object, GAsyncResult *res, gpointer user_data) + { + NMRemoteConnection *remote_con = NM_REMOTE_CONNECTION(source_object); + wifiManager *_wifiManager = (static_cast(user_data)); + GVariant *ret = NULL; + GError *error = NULL; + + ret = nm_remote_connection_update2_finish(remote_con, res, &error); + + if (!ret) { + NMLOG_ERROR("Error: %s.", error->message); + g_error_free(error); + _wifiManager->quit(NULL); + return; + } + _wifiManager->createNewConnection = false; // no need to create new connection + nm_client_activate_connection_async( + _wifiManager->client, NM_CONNECTION(remote_con), _wifiManager->wifidevice, _wifiManager->objectPath, NULL, wifiConnectCb, _wifiManager); + } + + bool wifiManager::createClientNewConnection() + { + GError *error = NULL; + if(client != nullptr) + { + g_object_unref(client); + client = nullptr; + } + + client = nm_client_new(NULL, &error); + if (!client || !loop) { + NMLOG_ERROR("Could not connect to NetworkManager: %s.", error->message); + g_error_free(error); + return false; + } + return true; + } + + bool wifiManager::wifiConnect(const char *ssid_in, const char* password_in, Exchange::INetworkManager::WIFISecurityMode security_in) + { + NMAccessPoint *AccessPoint = NULL; + GPtrArray *allaps = NULL; + const char *conName = ssid_in; + NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWireless *s_wireless = NULL; + NMSettingWirelessSecurity *s_secure = NULL; + NM80211ApFlags apFlags; + NM80211ApSecurityFlags apWpaFlags; + NM80211ApSecurityFlags apRsnFlags; + const char *ifname = NULL; + const GPtrArray *availableConnections; + bool SSIDmatch = false; + Exchange::INetworkManager::WiFiSSIDInfo apinfo; + + if(!createClientNewConnection()) + return false; + + if (strlen(ssid_in) > 32) + { + NMLOG_WARNING("ssid length grater than 32"); + return false; + } + + NMDevice *device = NULL; + device = getNmDevice(); + if(device == NULL) + return false; + wifidevice = device; + + std::string activeSSID; + if(getConnectedSSID(NM_DEVICE_WIFI(wifidevice), activeSSID)) + { + if(strcmp(ssid_in, activeSSID.c_str()) == 0) + { + NMLOG_WARNING("ssid already connected !"); + return true; + } + else + { + NMLOG_WARNING("wifi already connected with %s AP", activeSSID.c_str()); + } + } + //NMLOG_TRACE("Wireless Device found ifce : %s !", ifname = nm_device_get_iface(device)); + AccessPoint = checkSSIDAvailable(device, allaps, ssid_in); + // TODO Scann hidden ssid also for lnf + if(AccessPoint == NULL) { + NMLOG_WARNING("No network with SSID '%s' found !", ssid_in); + return false; + } + + getApInfo(AccessPoint, apinfo); + + availableConnections = nm_device_get_available_connections(device); + for (guint i = 0; i < availableConnections->len; i++) + { + NMConnection *currentConnection = static_cast(g_ptr_array_index(availableConnections, i)); + const char *id = nm_connection_get_id(NM_CONNECTION(currentConnection)); + + if (conName) { + if (!id || strcmp(id, conName)) + continue; + + SSIDmatch = TRUE; + } + + if (nm_access_point_connection_valid(AccessPoint, NM_CONNECTION(currentConnection))) { + connection = g_object_ref(currentConnection); + NMLOG_INFO("Connection '%s' exists !", conName); + break; + } + } + + if (SSIDmatch && !connection) + { + NMLOG_ERROR("Connection '%s' exists but properties don't match.", conName); + //TODO Remove Connection + return false; + } + + if (!connection) + { + NMLOG_TRACE("creating new connection '%s' .", conName); + connection = nm_simple_connection_new(); + if (conName) { + s_con = (NMSettingConnection *) nm_setting_connection_new(); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + const char *uuid = nm_utils_uuid_generate();; + + g_object_set(G_OBJECT(s_con), + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_ID, + conName, + NM_SETTING_CONNECTION_TYPE, + "802-11-wireless", + NULL); + } + + s_wireless = (NMSettingWireless *)nm_setting_wireless_new(); + GBytes *ssid = g_bytes_new(ssid_in, strlen(ssid_in)); + g_object_set(G_OBJECT(s_wireless), + NM_SETTING_WIRELESS_SSID, + ssid, + NULL); + //g_bytes_unref(ssid); + /* For lnf network need to include + * + * 'bssid' parameter is used to restrict the connection only to the BSSID + * g_object_set(s_wifi, NM_SETTING_WIRELESS_BSSID, bssid, NULL); + * g_object_set(s_wifi, NM_SETTING_WIRELESS_SSID, ssid, NM_SETTING_WIRELESS_HIDDEN, hidden, NULL); + */ + nm_connection_add_setting(connection, NM_SETTING(s_wireless)); + } + + apFlags = nm_access_point_get_flags(AccessPoint); + apWpaFlags = nm_access_point_get_wpa_flags(AccessPoint); + apRsnFlags = nm_access_point_get_rsn_flags(AccessPoint); + + // check ap flag ty securti we supporting + if(apFlags != NM_802_11_AP_FLAGS_NONE && strlen(password_in) < 1 ) + { + NMLOG_ERROR("This ap(%s) security need password please add password!", ssid_in); + return false; + } + + if ( (apRsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE) || (apRsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE_TM) + || (apWpaFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)|| (apRsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) ) { + + NMLOG_ERROR("Ap wifi security OWE and 802 1X mode not supported"); + return false; + } + + if ((apFlags & NM_802_11_AP_FLAGS_PRIVACY) || (apWpaFlags != NM_802_11_AP_SEC_NONE )|| (apRsnFlags != NM_802_11_AP_SEC_NONE )) + { + std::string flagStr; + apFlagsToString(apWpaFlags, flagStr); + apFlagsToString(apRsnFlags, flagStr); + NMLOG_INFO("%s ap securtity mode ( %s) supported !", ssid_in, flagStr.c_str()); + + if (password_in) + { + s_secure = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new(); + nm_connection_add_setting(connection, NM_SETTING(s_secure)); + + if (apWpaFlags == NM_802_11_AP_SEC_NONE && apRsnFlags == NM_802_11_AP_SEC_NONE) + { + nm_setting_wireless_security_set_wep_key(s_secure, 0, password_in); + NMLOG_ERROR("wifi security WEP mode not supported ! need to add wep-key-type"); + return false; + } + else if ((apWpaFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (apRsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) || (apRsnFlags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { + + g_object_set(G_OBJECT(s_secure), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,"wpa-psk", NULL); + g_object_set(G_OBJECT(s_secure), NM_SETTING_WIRELESS_SECURITY_PSK, password_in, NULL); + } + } + else + { + NMLOG_ERROR("This AccessPoint(%s) need password please add password!", ssid_in); + return false; + } + } + else + { + /* for open network every flag value will be zero */ + if (apFlags == NM_802_11_AP_FLAGS_NONE && apWpaFlags == NM_802_11_AP_SEC_NONE && apRsnFlags == NM_802_11_AP_SEC_NONE) { + NMLOG_INFO("open network no password requied"); + } + else { + NMLOG_ERROR("wifi security mode not supported !"); + return false; + } + } + + objectPath = nm_object_get_path(NM_OBJECT(AccessPoint)); + wifiDeviceStateGsignal = g_signal_connect(device, "notify::" NM_DEVICE_STATE, G_CALLBACK(connectGsignalCb), this); + GVariant *nmDbusConnection = nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL); + if (NM_IS_REMOTE_CONNECTION(connection)) + { + nm_remote_connection_update2(NM_REMOTE_CONNECTION(connection), + nmDbusConnection, + NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT, // autoconnect right away + NULL, + NULL, + wifiConnectionUpdate, + this); + } + else + { + createNewConnection = true; + nm_client_add_and_activate_connection_async(client, connection, device, objectPath, NULL, wifiConnectCb, this); + } + + wait(loop); + NMLOG_TRACE("Exit"); + return true; + } + } // namespace Plugin +} // namespace WPEFramework diff --git a/NetworkManager/service/NetworkManagerGnomeWIFI.h b/NetworkManager/service/NetworkManagerGnomeWIFI.h new file mode 100644 index 0000000000..e3ce0f3b88 --- /dev/null +++ b/NetworkManager/service/NetworkManagerGnomeWIFI.h @@ -0,0 +1,82 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "NetworkManagerLogger.h" +#include "INetworkManager.h" +#include +#include +#include +#include +#include + +namespace WPEFramework +{ + namespace Plugin + { + class wifiManager + { + public: + static wifiManager* getInstance() + { + static wifiManager instance; + return &instance; + } + + bool isWifiConnected(); + bool wifiDisconnect(); + bool wifiConnectedSSIDInfo(Exchange::INetworkManager::WiFiSSIDInfo &ssidinfo); + bool wifiConnect(const char *ssid_in, const char* password_in, Exchange::INetworkManager::WIFISecurityMode security_in); + bool quit(NMDevice *wifiNMDevice); + bool wait(GMainLoop *loop); + private: + NMDevice *getNmDevice(); + + private: + wifiManager() : client(nullptr), loop(nullptr), createNewConnection(false) { + loop = g_main_loop_new(NULL, FALSE); + } + ~wifiManager() { + NMLOG_TRACE("~wifiManager"); + if(client != nullptr) + g_object_unref(client); + if (loop != NULL) { + g_main_loop_unref(loop); + loop = NULL; + } + } + + wifiManager(wifiManager const&) = delete; + void operator=(wifiManager const&) = delete; + + bool createClientNewConnection(); + + public: + NMClient *client; + GMainLoop *loop; + gboolean createNewConnection; + const char* objectPath; + NMDevice *wifidevice; + guint wifiDeviceStateGsignal = 0; + }; + } +} diff --git a/NetworkManager/service/NetworkManagerImplementation.cpp b/NetworkManager/service/NetworkManagerImplementation.cpp new file mode 100644 index 0000000000..f2431d982f --- /dev/null +++ b/NetworkManager/service/NetworkManagerImplementation.cpp @@ -0,0 +1,533 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* 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 "NetworkManagerImplementation.h" +#include "NetworkConnectivity.h" +#include "WifiSignalStrengthMonitor.h" + +using namespace WPEFramework; +using namespace WPEFramework::Plugin; +using namespace NetworkManagerLogger; + +#define CIDR_NETMASK_IP_LEN 32 + +namespace WPEFramework +{ + namespace Plugin + { + SERVICE_REGISTRATION(NetworkManagerImplementation, NETWORKMANAGER_MAJOR_VERSION, NETWORKMANAGER_MINOR_VERSION, NETWORKMANAGER_PATCH_VERSION); + + NetworkManagerImplementation::NetworkManagerImplementation() + : _notificationCallbacks({}) + { + /* Initialize Network Manager */ + NetworkManagerLogger::Init(); + + LOG_ENTRY_FUNCTION(); + /* Name says it all */ + platform_init(); + + /* Initialize STUN Endpoints */ + m_stunEndPoint = "stun.l.google.com"; + m_stunPort = 19302; + m_stunBindTimeout = 30; + m_stunCacheTimeout = 0; + m_defaultInterface = ""; + m_publicIP = ""; + } + + NetworkManagerImplementation::~NetworkManagerImplementation() + { + connectivityMonitor.stopContinuousConnectivityMonitoring(); + LOG_ENTRY_FUNCTION(); + } + + /** + * Register a notification callback + */ + uint32_t NetworkManagerImplementation::Register(INetworkManager::INotification *notification) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + + // Make sure we can't register the same notification callback multiple times + if (std::find(_notificationCallbacks.begin(), _notificationCallbacks.end(), notification) == _notificationCallbacks.end()) { + _notificationCallbacks.push_back(notification); + notification->AddRef(); + } + + _notificationLock.Unlock(); + + return Core::ERROR_NONE; + } + + /** + * Unregister a notification callback + */ + uint32_t NetworkManagerImplementation::Unregister(INetworkManager::INotification *notification) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + + // Make sure we can't register the same notification callback multiple times + auto itr = std::find(_notificationCallbacks.begin(), _notificationCallbacks.end(), notification); + if (itr != _notificationCallbacks.end()) { + (*itr)->Release(); + _notificationCallbacks.erase(itr); + } + + _notificationLock.Unlock(); + + return Core::ERROR_NONE; + } + + uint32_t NetworkManagerImplementation::Configure(const string& configLine /* @in */, NMLogging& logLevel /* @out */) + { + if(configLine.empty()) + { + NMLOG_FATAL("config line : is empty !"); + return(Core::ERROR_GENERAL); + } + + NMLOG_TRACE("config line : %s", configLine.c_str()); + + Config config; + if(config.FromString(configLine)) + { + /* stun configuration copy */ + m_stunEndPoint = config.stun.stunEndpoint.Value(); + m_stunPort = config.stun.port.Value(); + m_stunBindTimeout = config.stun.interval.Value(); + + NMLOG_TRACE("config : stun endpoint %s", m_stunEndPoint.c_str()); + NMLOG_TRACE("config : stun port %d", m_stunPort); + NMLOG_TRACE("config : stun interval %d", m_stunBindTimeout); + + NMLOG_TRACE("config : endpoint 1 %s", config.connectivity.endpoint_1.Value().c_str()); + NMLOG_TRACE("config : endpoint 2 %s", config.connectivity.endpoint_2.Value().c_str()); + NMLOG_TRACE("config : endpoint 3 %s", config.connectivity.endpoint_3.Value().c_str()); + NMLOG_TRACE("config : endpoint 4 %s", config.connectivity.endpoint_4.Value().c_str()); + NMLOG_TRACE("config : endpoint 5 %s", config.connectivity.endpoint_5.Value().c_str()); + NMLOG_TRACE("config : interval %d", config.connectivity.ConnectivityCheckInterval.Value()); + + NMLOG_TRACE("config : loglevel %d", config.loglevel.Value()); + logLevel = static_cast (config.loglevel.Value()); + // configure loglevel in libWPEFrameworkNetworkManagerImplementation.so + NetworkManagerLogger::SetLevel(static_cast (logLevel)); + + std::vector endpoints; + endpoints.push_back(config.connectivity.endpoint_1.Value().c_str()); + endpoints.push_back(config.connectivity.endpoint_2.Value().c_str()); + endpoints.push_back(config.connectivity.endpoint_3.Value().c_str()); + endpoints.push_back(config.connectivity.endpoint_4.Value().c_str()); + endpoints.push_back(config.connectivity.endpoint_5.Value().c_str()); + + //set connectivity endpoint + connectivityMonitor.setConnectivityMonitorEndpoints(endpoints); + } + else + NMLOG_ERROR("Plugin configuration read error !"); + + return(Core::ERROR_NONE); + } + + /* @brief Get STUN Endpoint to be used for identifying Public IP */ + uint32_t NetworkManagerImplementation::GetStunEndpoint (string &endPoint /* @out */, uint32_t& port /* @out */, uint32_t& bindTimeout /* @out */, uint32_t& cacheTimeout /* @out */) const + { + LOG_ENTRY_FUNCTION(); + endPoint = m_stunEndPoint; + port = m_stunPort; + bindTimeout = m_stunBindTimeout; + cacheTimeout = m_stunCacheTimeout; + return Core::ERROR_NONE; + } + + /* @brief Set STUN Endpoint to be used to identify Public IP */ + uint32_t NetworkManagerImplementation::SetStunEndpoint (string const endPoint /* @in */, const uint32_t port /* @in */, const uint32_t bindTimeout /* @in */, const uint32_t cacheTimeout /* @in */) + { + LOG_ENTRY_FUNCTION(); + if (!endPoint.empty()) + m_stunEndPoint = endPoint; + if (port != 0) + m_stunPort = port; + + m_stunBindTimeout = bindTimeout; + m_stunCacheTimeout = cacheTimeout; + return Core::ERROR_NONE; + } + + /* @brief Get ConnectivityTest Endpoints */ + uint32_t NetworkManagerImplementation::GetConnectivityTestEndpoints(IStringIterator*& endPoints/* @out */) const + { + LOG_ENTRY_FUNCTION(); + std::vector tmpEndPoints = connectivityMonitor.getConnectivityMonitorEndpoints(); + endPoints = (Core::Service::Create(tmpEndPoints)); + + return Core::ERROR_NONE; + } + + /* @brief Set ConnectivityTest Endpoints */ + uint32_t NetworkManagerImplementation::SetConnectivityTestEndpoints(IStringIterator* const endPoints /* @in */) + { + LOG_ENTRY_FUNCTION(); + std::vector tmpEndPoints; + if(endPoints) + { + string endPoint{}; + while (endPoints->Next(endPoint) == true) + { + tmpEndPoints.push_back(endPoint); + } + connectivityMonitor.setConnectivityMonitorEndpoints(tmpEndPoints); + } + return Core::ERROR_NONE; + } + + /* @brief Get Internet Connectivty Status */ + uint32_t NetworkManagerImplementation::IsConnectedToInternet(const string &ipversion /* @in */, InternetStatus &result /* @out */) + { + LOG_ENTRY_FUNCTION(); + nsm_internetState isconnected; + nsm_ipversion tmpVersion = NSM_IPRESOLVE_WHATEVER; + if(0 == strcasecmp("IPv4", ipversion.c_str())) + tmpVersion = NSM_IPRESOLVE_V4; + else if(0 == strcasecmp("IPv6", ipversion.c_str())) + tmpVersion = NSM_IPRESOLVE_V6; + + isconnected = connectivityMonitor.getInternetConnectionState(tmpVersion); + if (FULLY_CONNECTED == isconnected) + result = INTERNET_FULLY_CONNECTED; + else if (CAPTIVE_PORTAL == isconnected) + result = INTERNET_CAPTIVE_PORTAL; + else if (LIMITED_INTERNET == isconnected) + result = INTERNET_LIMITED; + else + result = INTERNET_NOT_AVAILABLE; + + return Core::ERROR_NONE; + } + + /* @brief Get Authentication URL if the device is behind Captive Portal */ + uint32_t NetworkManagerImplementation::GetCaptivePortalURI(string &endPoints/* @out */) const + { + LOG_ENTRY_FUNCTION(); + endPoints = connectivityMonitor.getCaptivePortalURI(); + return Core::ERROR_NONE; + } + + /* @brief Start The Internet Connectivity Monitoring */ + uint32_t NetworkManagerImplementation::StartConnectivityMonitoring(const uint32_t interval/* @in */) + { + LOG_ENTRY_FUNCTION(); + if (connectivityMonitor.doContinuousConnectivityMonitoring(interval)) + return Core::ERROR_NONE; + else + return Core::ERROR_GENERAL; + } + + /* @brief Stop The Internet Connectivity Monitoring */ + uint32_t NetworkManagerImplementation::StopConnectivityMonitoring(void) const + { + LOG_ENTRY_FUNCTION(); + if (connectivityMonitor.stopContinuousConnectivityMonitoring()) + return Core::ERROR_NONE; + else + return Core::ERROR_GENERAL; + } + + /* @brief Get the Public IP used for external world communication */ + uint32_t NetworkManagerImplementation::GetPublicIP (const string &ipversion /* @in */, string& ipAddress /* @out */) + { + LOG_ENTRY_FUNCTION(); + stun::bind_result result; + bool isIPv6 = (0 == strcasecmp("IPv6", ipversion.c_str())); + stun::protocol proto (isIPv6 ? stun::protocol::af_inet6 : stun::protocol::af_inet); + if(stunClient.bind(m_stunEndPoint, m_stunPort, m_defaultInterface, proto, m_stunBindTimeout, m_stunCacheTimeout, result)) + { + ipAddress = result.public_ip; + return Core::ERROR_NONE; + } + else + { + return Core::ERROR_GENERAL; + } + } + + /* @brief Set the network manager plugin log level */ + uint32_t NetworkManagerImplementation::SetLogLevel(const NMLogging& logLevel /* @in */) + { + NetworkManagerLogger::SetLevel((LogLevel)logLevel); + return Core::ERROR_NONE; + } + + /* @brief Request for ping and get the response in as event. The GUID used in the request will be returned in the event. */ + uint32_t NetworkManagerImplementation::Ping (const string ipversion /* @in */, const string endpoint /* @in */, const uint32_t noOfRequest /* @in */, const uint16_t timeOutInSeconds /* @in */, const string guid /* @in */, string& response /* @out */) + { + char cmd[100] = ""; + if(0 == strcasecmp("IPv6", ipversion.c_str())) + { + snprintf(cmd, sizeof(cmd), "ping6 -c %d -W %d '%s' 2>&1", noOfRequest, timeOutInSeconds, endpoint.c_str()); + } + else + { + snprintf(cmd, sizeof(cmd), "ping -c %d -W %d '%s' 2>&1", noOfRequest, timeOutInSeconds, endpoint.c_str()); + } + + NMLOG_INFO ("The Command is %s", cmd); + string commandToExecute(cmd); + executeExternally(NETMGR_PING, commandToExecute, response); + + return Core::ERROR_NONE; + } + + /* @brief Request for trace get the response in as event. The GUID used in the request will be returned in the event. */ + uint32_t NetworkManagerImplementation::Trace (const string ipversion /* @in */, const string endpoint /* @in */, const uint32_t noOfRequest /* @in */, const string guid /* @in */, string& response /* @out */) + { + char cmd[256] = ""; + if(0 == strcasecmp("IPv6", ipversion.c_str())) + { + snprintf(cmd, 256, "traceroute6 -w 3 -m 6 -q %d %s 64 2>&1", noOfRequest, endpoint.c_str()); + } + else + { + snprintf(cmd, 256, "traceroute -w 3 -m 6 -q %d %s 52 2>&1", noOfRequest, endpoint.c_str()); + } + + NMLOG_INFO ("The Command is %s", cmd); + string commandToExecute(cmd); + executeExternally(NETMGR_TRACE, commandToExecute, response); + + return Core::ERROR_NONE; + } + + void NetworkManagerImplementation::executeExternally(NetworkEvents event, const string commandToExecute, string& response) + { + FILE *pipe = NULL; + string output{}; + char buffer[1024]; + JsonObject pingResult; + + pipe = popen(commandToExecute.c_str(), "r"); + if (pipe == NULL) + { + NMLOG_INFO ("%s: failed to open file '%s' for read mode with result: %s", __FUNCTION__, commandToExecute.c_str(), strerror(errno)); + return; + } + + if (NETMGR_PING == event) + { + while (!feof(pipe) && fgets(buffer, 1024, pipe) != NULL) + { + // remove newline from buffer + buffer[strcspn(buffer, "\n")] = '\0'; + string line(buffer); + + if( line.find( "packet" ) != string::npos ) + { + //Example: 10 packets transmitted, 10 packets received, 0% packet loss + stringstream ss( line ); + int transCount; + ss >> transCount; + pingResult["packetsTransmitted"] = transCount; + + string token; + getline( ss, token, ',' ); + getline( ss, token, ',' ); + stringstream ss2( token ); + int rxCount; + ss2 >> rxCount; + pingResult["packetsReceived"] = rxCount; + + getline( ss, token, ',' ); + string prefix = token.substr(0, token.find("%")); + pingResult["packetLoss"] = prefix.c_str(); + + } + else if( line.find( "min/avg/max" ) != string::npos ) + { + //Example: round-trip min/avg/max = 17.038/18.310/20.197 ms + stringstream ss( line ); + string fullpath; + getline( ss, fullpath, '=' ); + getline( ss, fullpath, '=' ); + + string prefix; + int index = fullpath.find("/"); + if (index >= 0) + { + prefix = fullpath.substr(0, fullpath.find("/")); + pingResult["tripMin"] = prefix.c_str(); + } + + index = fullpath.find("/"); + if (index >= 0) + { + fullpath = fullpath.substr(index + 1, fullpath.length()); + prefix = fullpath.substr(0, fullpath.find("/")); + pingResult["tripAvg"] = prefix.c_str(); + } + + index = fullpath.find("/"); + if (index >= 0) + { + fullpath = fullpath.substr(index + 1, fullpath.length()); + prefix = fullpath.substr(0, fullpath.find("/")); + pingResult["tripMax"] = prefix.c_str(); + } + + index = fullpath.find("/"); + if (index >= 0) + { + fullpath = fullpath.substr(index + 1, fullpath.length()); + pingResult["tripStdDev"] = fullpath.c_str(); + } + } + else if( line.find( "bad" ) != string::npos ) + { + pingResult["success"] = false; + pingResult["error"] = "Bad Address"; + } + } + + pingResult.ToString(response); + NMLOG_INFO("Response is, %s", response.c_str()); + } + else if (NETMGR_TRACE == event) + { + + // We return the entire output of the trace command but since this contains newlines it is not valid as + // a json value so we will parse the output into an array of strings, one element for each line. + JsonArray list; + while (!feof(pipe) && fgets(buffer, 1024, pipe) != NULL) + { + // remove newline from buffer + buffer[strcspn(buffer, "\n")] = '\0'; + string line(buffer); + list.Add(line); + } + + list.ToString(response); + NMLOG_INFO("Response is, %s", response.c_str()); + } + fclose(pipe); + return; + } + + // WiFi Specific Methods + /* @brief Initiate a WIFI Scan; This is Async method and returns the scan results as Event */ + uint32_t NetworkManagerImplementation::GetSupportedSecurityModes(ISecurityModeIterator*& securityModes /* @out */) const + { + LOG_ENTRY_FUNCTION(); + std::vector modeInfo { + {WIFI_SECURITY_NONE, "WIFI_SECURITY_NONE"}, + {WIFI_SECURITY_WEP_64, "WIFI_SECURITY_WEP_64"}, + {WIFI_SECURITY_WEP_128, "WIFI_SECURITY_WEP_128"}, + {WIFI_SECURITY_WPA_PSK_TKIP, "WIFI_SECURITY_WPA_PSK_TKIP"}, + {WIFI_SECURITY_WPA_PSK_AES, "WIFI_SECURITY_WPA_PSK_AES"}, + {WIFI_SECURITY_WPA2_PSK_TKIP, "WIFI_SECURITY_WPA2_PSK_TKIP"}, + {WIFI_SECURITY_WPA2_PSK_AES, "WIFI_SECURITY_WPA2_PSK_AES"}, + {WIFI_SECURITY_WPA_ENTERPRISE_TKIP, "WIFI_SECURITY_WPA_ENTERPRISE_TKIP"}, + {WIFI_SECURITY_WPA_ENTERPRISE_AES, "WIFI_SECURITY_WPA_ENTERPRISE_AES"}, + {WIFI_SECURITY_WPA2_ENTERPRISE_TKIP, "WIFI_SECURITY_WPA2_ENTERPRISE_TKIP"}, + {WIFI_SECURITY_WPA2_ENTERPRISE_AES, "WIFI_SECURITY_WPA2_ENTERPRISE_AES"}, + {WIFI_SECURITY_WPA_WPA2_PSK, "WIFI_SECURITY_WPA_WPA2_PSK"}, + {WIFI_SECURITY_WPA_WPA2_ENTERPRISE, "WIFI_SECURITY_WPA_WPA2_ENTERPRISE"}, + {WIFI_SECURITY_WPA3_PSK_AES, "WIFI_SECURITY_WPA3_PSK_AES"}, + {WIFI_SECURITY_WPA3_SAE, "WIFI_SECURITY_WPA3_SAE"} + }; + + using Implementation = RPC::IteratorType; + securityModes = Core::Service::Create(modeInfo); + + return Core::ERROR_NONE; + } + + void NetworkManagerImplementation::ReportInterfaceStateChangedEvent(INetworkManager::InterfaceState state, string interface) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + for (const auto callback : _notificationCallbacks) { + callback->onInterfaceStateChange(state, interface); + } + _notificationLock.Unlock(); + } + + void NetworkManagerImplementation::ReportIPAddressChangedEvent(const string& interface, bool isAcquired, bool isIPv6, const string& ipAddress) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + for (const auto callback : _notificationCallbacks) { + callback->onIPAddressChange(interface, isAcquired, isIPv6, ipAddress); + } + _notificationLock.Unlock(); + } + + void NetworkManagerImplementation::ReportActiveInterfaceChangedEvent(const string prevActiveInterface, const string currentActiveinterface) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + for (const auto callback : _notificationCallbacks) { + callback->onActiveInterfaceChange(prevActiveInterface, currentActiveinterface); + } + _notificationLock.Unlock(); + } + + void NetworkManagerImplementation::ReportInternetStatusChangedEvent(const InternetStatus oldState, const InternetStatus newstate) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + for (const auto callback : _notificationCallbacks) { + callback->onInternetStatusChange(oldState, newstate); + } + _notificationLock.Unlock(); + } + + void NetworkManagerImplementation::ReportAvailableSSIDsEvent(const string jsonOfWiFiScanResults) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + NMLOG_INFO("scan result is, %s", jsonOfWiFiScanResults.c_str()); + for (const auto callback : _notificationCallbacks) { + callback->onAvailableSSIDs(jsonOfWiFiScanResults); + } + _notificationLock.Unlock(); + } + + void NetworkManagerImplementation::ReportWiFiStateChangedEvent(const INetworkManager::WiFiState state) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + for (const auto callback : _notificationCallbacks) { + callback->onWiFiStateChange(state); + } + _notificationLock.Unlock(); + } + + void NetworkManagerImplementation::ReportWiFiSignalStrengthChangedEvent(const string ssid, const string signalLevel, const WiFiSignalQuality signalQuality) + { + LOG_ENTRY_FUNCTION(); + _notificationLock.Lock(); + for (const auto callback : _notificationCallbacks) { + callback->onWiFiSignalStrengthChange(ssid, signalLevel, signalQuality); + + } + _notificationLock.Unlock(); + } + } +} diff --git a/NetworkManager/service/NetworkManagerImplementation.h b/NetworkManager/service/NetworkManagerImplementation.h new file mode 100644 index 0000000000..20b018e631 --- /dev/null +++ b/NetworkManager/service/NetworkManagerImplementation.h @@ -0,0 +1,242 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ + +#pragma once + + +#include "Module.h" +#include +#include +#include +#include + +using namespace std; + +//#include +#include "INetworkManager.h" +#include "NetworkManagerLogger.h" +#include "WifiSignalStrengthMonitor.h" +#include "NetworkConnectivity.h" +#include "StunClient.h" + +#define LOG_ENTRY_FUNCTION() { NMLOG_TRACE("Entering=%s", __FUNCTION__ ); } + +namespace WPEFramework +{ + namespace Plugin + { + class NetworkManagerImplementation : public Exchange::INetworkManager + { + enum NetworkEvents { + NETMGR_PING, + NETMGR_TRACE, + }; + + class Config : public Core::JSON::Container { + private: + Config(const Config&); + Config& operator=(const Config&); + + public: + class Connectivity : public Core::JSON::Container { + public: + Connectivity& operator=(const Connectivity&) = delete; + + Connectivity() + : Core::JSON::Container() + , endpoint_1(_T("http://clients3.google.com/generate_204")) + , endpoint_2(_T("")) + , endpoint_3(_T("")) + , endpoint_4(_T("")) + , endpoint_5(_T("")) + , ConnectivityCheckInterval(6) + { + Add(_T("endpoint_1"), &endpoint_1); + Add(_T("endpoint_2"), &endpoint_2); + Add(_T("endpoint_3"), &endpoint_3); + Add(_T("endpoint_4"), &endpoint_4); + Add(_T("endpoint_5"), &endpoint_5); + Add(_T("interval"), &ConnectivityCheckInterval); + } + ~Connectivity() override = default; + + public: + /* connectivity configuration */ + Core::JSON::String endpoint_1; + Core::JSON::String endpoint_2; + Core::JSON::String endpoint_3; + Core::JSON::String endpoint_4; + Core::JSON::String endpoint_5; + Core::JSON::DecUInt32 ConnectivityCheckInterval; + }; + + class Stun : public Core::JSON::Container { + public: + Stun& operator=(const Stun&) = delete; + + Stun() + : Core::JSON::Container() + , stunEndpoint(_T("")) + , port(19310) + , interval(30) + { + Add(_T("endpoint"), &stunEndpoint); + Add(_T("port"), &port); + Add(_T("interval"), &interval); + } + ~Stun() override = default; + + public: + /* stun configuration */ + Core::JSON::String stunEndpoint; + Core::JSON::DecUInt32 port; + Core::JSON::DecUInt32 interval; + }; + + public: + Config() + : Core::JSON::Container() + { + Add(_T("connectivity"), &connectivity); + Add(_T("stun"), &stun); + Add(_T("loglevel"), &loglevel); + } + ~Config() override = default; + + public: + Connectivity connectivity; + Stun stun; + Core::JSON::DecUInt32 loglevel; + }; + + public: + NetworkManagerImplementation(); + ~NetworkManagerImplementation() override; + + // Do not allow copy/move constructors + NetworkManagerImplementation(const NetworkManagerImplementation &) = delete; + NetworkManagerImplementation &operator=(const NetworkManagerImplementation &) = delete; + + BEGIN_INTERFACE_MAP(NetworkManagerImplementation) + INTERFACE_ENTRY(Exchange::INetworkManager) + END_INTERFACE_MAP + + // Handle Notification registration/removal + uint32_t Register(INetworkManager::INotification *notification) override; + uint32_t Unregister(INetworkManager::INotification *notification) override; + + public: + // Below Control APIs will work with RDK or GNome NW. + /* @brief Get all the Available Interfaces */ + uint32_t GetAvailableInterfaces (IInterfaceDetailsIterator*& interfaces/* @out */) override; + + /* @brief Get the active Interface used for external world communication */ + uint32_t GetPrimaryInterface (string& interface /* @out */) override; + /* @brief Set the active Interface used for external world communication */ + uint32_t SetPrimaryInterface (const string& interface/* @in */) override; + + uint32_t EnableInterface (const string& interface/* @in */) override; + uint32_t DisableInterface (const string& interface/* @in */) override; + /* @brief Get IP Address Of the Interface */ + uint32_t GetIPSettings(const string& interface /* @in */, const string &ipversion /* @in */, IPAddressInfo& result /* @out */) override; + /* @brief Set IP Address Of the Interface */ + uint32_t SetIPSettings(const string& interface /* @in */, const string &ipversion /* @in */, const IPAddressInfo& address /* @in */) override; + + // WiFi Specific Methods + /* @brief Initiate a WIFI Scan; This is Async method and returns the scan results as Event */ + uint32_t StartWiFiScan(const WiFiFrequency frequency /* @in */); + uint32_t StopWiFiScan(void) override; + + uint32_t GetKnownSSIDs(IStringIterator*& ssids /* @out */) override; + uint32_t AddToKnownSSIDs(const WiFiConnectTo& ssid /* @in */) override; + uint32_t RemoveKnownSSID(const string& ssid /* @in */) override; + + uint32_t WiFiConnect(const WiFiConnectTo& ssid /* @in */) override; + uint32_t WiFiDisconnect(void) override; + uint32_t GetConnectedSSID(WiFiSSIDInfo& ssidInfo /* @out */) override; + + uint32_t StartWPS(const WiFiWPS& method /* @in */, const string& wps_pin /* @in */) override; + uint32_t StopWPS(void) override; + uint32_t GetWifiState(WiFiState &state) override; + uint32_t GetWiFiSignalStrength(string& ssid /* @out */, string& signalStrength /* @out */, WiFiSignalQuality& quality /* @out */) override; + + uint32_t SetStunEndpoint (string const endPoint /* @in */, const uint32_t port /* @in */, const uint32_t bindTimeout /* @in */, const uint32_t cacheTimeout /* @in */) override; + uint32_t GetStunEndpoint (string &endPoint /* @out */, uint32_t& port /* @out */, uint32_t& bindTimeout /* @out */, uint32_t& cacheTimeout /* @out */) const override; + + /* @brief Get ConnectivityTest Endpoints */ + uint32_t GetConnectivityTestEndpoints(IStringIterator*& endPoints/* @out */) const override; + /* @brief Set ConnectivityTest Endpoints */ + uint32_t SetConnectivityTestEndpoints(IStringIterator* const endPoints /* @in */) override; + + /* @brief Get Internet Connectivty Status */ + uint32_t IsConnectedToInternet(const string &ipversion /* @in */, InternetStatus &result /* @out */) override; + /* @brief Get Authentication URL if the device is behind Captive Portal */ + uint32_t GetCaptivePortalURI(string &endPoints/* @out */) const override; + + /* @brief Start The Internet Connectivity Monitoring */ + uint32_t StartConnectivityMonitoring(const uint32_t interval/* @in */) override; + /* @brief Stop The Internet Connectivity Monitoring */ + uint32_t StopConnectivityMonitoring(void) const override; + + /* @brief Get the Public IP used for external world communication */ + uint32_t GetPublicIP (const string &ipversion /* @in */, string& ipAddress /* @out */) override; + + /* @brief Request for ping and get the response in as event. The GUID used in the request will be returned in the event. */ + uint32_t Ping (const string ipversion /* @in */, const string endpoint /* @in */, const uint32_t noOfRequest /* @in */, const uint16_t timeOutInSeconds /* @in */, const string guid /* @in */, string& response /* @out */) override; + + /* @brief Request for trace get the response in as event. The GUID used in the request will be returned in the event. */ + uint32_t Trace (const string ipversion /* @in */, const string endpoint /* @in */, const uint32_t noOfRequest /* @in */, const string guid /* @in */, string& response /* @out */) override; + + uint32_t GetSupportedSecurityModes(ISecurityModeIterator*& securityModes /* @out */) const override; + + /* @brief Set the network manager plugin log level */ + uint32_t SetLogLevel(const NMLogging& logLevel /* @in */) override; + + /* @brief configure network manager plugin */ + uint32_t Configure(const string& configLine /* @in */, NMLogging& logLevel /* @out */) override; + + /* Events */ + void ReportInterfaceStateChangedEvent(INetworkManager::InterfaceState state, string interface); + void ReportIPAddressChangedEvent(const string& interface, bool isAcquired, bool isIPv6, const string& ipAddress); + void ReportActiveInterfaceChangedEvent(const string prevActiveInterface, const string currentActiveinterface); + void ReportInternetStatusChangedEvent(const InternetStatus oldState, const InternetStatus newstate); + void ReportAvailableSSIDsEvent(const string jsonOfWiFiScanResults); + void ReportWiFiStateChangedEvent(const INetworkManager::WiFiState state); + void ReportWiFiSignalStrengthChangedEvent(const string ssid , const string signalLevel , const WiFiSignalQuality signalQuality); + + private: + void platform_init(); + void executeExternally(NetworkEvents event, const string commandToExecute, string& response); + + private: + std::list _notificationCallbacks; + Core::CriticalSection _notificationLock; + string m_defaultInterface; + string m_publicIP; + stun::client stunClient; + string m_stunEndPoint; + uint16_t m_stunPort; + uint16_t m_stunBindTimeout; + uint16_t m_stunCacheTimeout; + public: + WifiSignalStrengthMonitor wifiSignalStrengthMonitor; + mutable ConnectivityMonitor connectivityMonitor; + }; + } +} diff --git a/NetworkManager/service/NetworkManagerJsonRpc.cpp b/NetworkManager/service/NetworkManagerJsonRpc.cpp new file mode 100644 index 0000000000..82c1e375af --- /dev/null +++ b/NetworkManager/service/NetworkManagerJsonRpc.cpp @@ -0,0 +1,954 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* 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 "NetworkManager.h" + +#define LOGINFOMETHOD() { std::string json; parameters.ToString(json); NMLOG_TRACE("params=%s", json.c_str() ); } +#define LOGTRACEMETHODFIN() { std::string json; response.ToString(json); NMLOG_TRACE("response=%s", json.c_str() ); } + +using namespace NetworkManagerLogger; + +namespace WPEFramework +{ + namespace Plugin + { + /** + * Hook up all our JSON RPC methods + * + * Each method definition comprises of: + * * Input parameters + * * Output parameters + * * Method name + * * Function that implements that method + */ + void NetworkManager::RegisterAllMethods() + { + Register("SetLogLevel", &NetworkManager::SetLogLevel, this); + Register("GetAvailableInterfaces", &NetworkManager::GetAvailableInterfaces, this); + Register("GetPrimaryInterface", &NetworkManager::GetPrimaryInterface, this); + Register("SetPrimaryInterface", &NetworkManager::SetPrimaryInterface, this); + Register("EnableInterface", &NetworkManager::EnableInterface, this); + Register("DisableInterface", &NetworkManager::DisableInterface, this); + Register("GetIPSettings", &NetworkManager::GetIPSettings, this); + Register("SetIPSettings", &NetworkManager::SetIPSettings, this); + Register("GetStunEndpoint", &NetworkManager::GetStunEndpoint, this); + Register("SetStunEndpoint", &NetworkManager::SetStunEndpoint, this); + Register("GetConnectivityTestEndpoints", &NetworkManager::GetConnectivityTestEndpoints, this); + Register("SetConnectivityTestEndpoints", &NetworkManager::SetConnectivityTestEndpoints, this); + Register("IsConnectedToInternet", &NetworkManager::IsConnectedToInternet, this); + Register("GetCaptivePortalURI", &NetworkManager::GetCaptivePortalURI, this); + Register("StartConnectivityMonitoring", &NetworkManager::StartConnectivityMonitoring, this); + Register("StopConnectivityMonitoring", &NetworkManager::StopConnectivityMonitoring, this); + Register("GetPublicIP", &NetworkManager::GetPublicIP, this); + Register("Ping", &NetworkManager::Ping, this); + Register("Trace", &NetworkManager::Trace, this); + Register("StartWiFiScan", &NetworkManager::StartWiFiScan, this); + Register("StopWiFiScan", &NetworkManager::StopWiFiScan, this); + Register("GetKnownSSIDs", &NetworkManager::GetKnownSSIDs, this); + Register("AddToKnownSSIDs", &NetworkManager::AddToKnownSSIDs, this); + Register("RemoveKnownSSID", &NetworkManager::RemoveKnownSSID, this); + Register("WiFiConnect", &NetworkManager::WiFiConnect, this); + Register("WiFiDisconnect", &NetworkManager::WiFiDisconnect, this); + Register("GetConnectedSSID", &NetworkManager::GetConnectedSSID, this); + Register("StartWPS", &NetworkManager::StartWPS, this); + Register("StopWPS", &NetworkManager::StopWPS, this); + Register("GetWifiState", &NetworkManager::GetWifiState, this); + Register("GetWiFiSignalStrength", &NetworkManager::GetWiFiSignalStrength, this); + Register("GetSupportedSecurityModes", &NetworkManager::GetSupportedSecurityModes, this); + } + + /** + * Unregister all our JSON-RPC methods + */ + void NetworkManager::UnregisterAllMethods() + { + Unregister("SetLogLevel"); + Unregister("GetAvailableInterfaces"); + Unregister("GetPrimaryInterface"); + Unregister("SetPrimaryInterface"); + Unregister("EnableInterface"); + Unregister("DisableInterface"); + Unregister("GetIPSettings"); + Unregister("SetIPSettings"); + Unregister("GetStunEndpoint"); + Unregister("SetStunEndpoint"); + Unregister("GetConnectivityTestEndpoints"); + Unregister("SetConnectivityTestEndpoints"); + Unregister("IsConnectedToInternet"); + Unregister("GetCaptivePortalURI"); + Unregister("StartConnectivityMonitoring"); + Unregister("StopConnectivityMonitoring"); + Unregister("GetPublicIP"); + Unregister("Ping"); + Unregister("Trace"); + Unregister("StartWiFiScan"); + Unregister("StopWiFiScan"); + Unregister("GetKnownSSIDs"); + Unregister("AddToKnownSSIDs"); + Unregister("RemoveKnownSSID"); + Unregister("WiFiConnect"); + Unregister("WiFiDisconnect"); + Unregister("GetConnectedSSID"); + Unregister("StartWPS"); + Unregister("StopWPS"); + Unregister("GetWifiState"); + Unregister("GetWiFiSignalStrength"); + Unregister("GetSupportedSecurityModes"); + } + + uint32_t NetworkManager::SetLogLevel (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + + uint32_t rc = Core::ERROR_GENERAL; + LogLevel level = INFO_LEVEL; + if (parameters.HasLabel("logLevel")) + { + level = static_cast (parameters["logLevel"].Number()); + + NetworkManagerLogger::SetLevel(level); + + const Exchange::INetworkManager::NMLogging log = static_cast (level); + if (_NetworkManager) + rc = _NetworkManager->SetLogLevel(log); + else + rc = Core::ERROR_UNAVAILABLE; + } + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetAvailableInterfaces (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::IInterfaceDetailsIterator* interfaces = NULL; + if (_NetworkManager) + rc = _NetworkManager->GetAvailableInterfaces(interfaces); + else + rc = Core::ERROR_UNAVAILABLE; + + if (interfaces) + { + NMLOG_TRACE("received response"); + JsonArray array; + Exchange::INetworkManager::InterfaceDetails entry{}; + while (interfaces->Next(entry) == true) { + JsonObject each; + each[_T("type")] = entry.m_type; + each[_T("name")] = entry.m_name; + each[_T("mac")] = entry.m_mac; + each[_T("isEnabled")] = entry.m_isEnabled; + each[_T("isConnected")] = entry.m_isConnected; + + array.Add(JsonValue(each)); + } + + interfaces->Release(); + NMLOG_TRACE("Sending Success"); + response["interfaces"] = array; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetPrimaryInterface (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string interface; + if (_NetworkManager) + rc = _NetworkManager->GetPrimaryInterface(interface); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["interface"] = interface; + m_defaultInterface = interface; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::SetPrimaryInterface (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string interface = parameters["interface"].String(); + if (_NetworkManager) + rc = _NetworkManager->SetPrimaryInterface(interface); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::EnableInterface (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string interface = parameters["interface"].String(); + if (_NetworkManager) + rc = _NetworkManager->EnableInterface(interface); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::DisableInterface (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string interface = parameters["interface"].String(); + if (_NetworkManager) + rc = _NetworkManager->DisableInterface(interface); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetIPSettings (const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + const string interface = parameters["interface"].String(); + const string ipversion = parameters["ipversion"].String(); + Exchange::INetworkManager::IPAddressInfo result{}; + + if (_NetworkManager) + rc = _NetworkManager->GetIPSettings(interface, ipversion, result); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["interface"] = interface; + if(result.m_ipAddrType == "IPV6" || result.m_ipAddrType == "IPV4") + result.m_ipAddrType[2] = tolower(result.m_ipAddrType[2]); + response["ipversion"] = result.m_ipAddrType; + response["autoconfig"] = result.m_autoConfig; + response["ipaddress"] = result.m_ipAddress; + response["prefix"] = result.m_prefix; + response["gateway"] = result.m_gateway; + response["dhcpserver"] = result.m_dhcpServer; + if(!result.m_v6LinkLocal.empty()) + response["v6LinkLocal"] = result.m_v6LinkLocal; + response["primarydns"] = result.m_primaryDns; + response["secondarydns"] = result.m_secondaryDns; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::SetIPSettings(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::IPAddressInfo result{}; + const string interface = parameters["interface"].String(); + const string ipversion = parameters["ipversion"].String(); + + result.m_autoConfig = parameters["autoconfig"].Boolean(); + if (!result.m_autoConfig) + { + result.m_ipAddress = parameters["ipaddress"]; + result.m_prefix = parameters["prefix"].Number(); + result.m_gateway = parameters["gateway"]; + result.m_primaryDns = parameters["primarydns"]; + result.m_secondaryDns = parameters["secondarydns"]; + } + + if (_NetworkManager) + rc = _NetworkManager->SetIPSettings(interface, ipversion, result); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetStunEndpoint(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string endPoint; + uint32_t port; + uint32_t bindTimeout; + uint32_t cacheTimeout; + + if (_NetworkManager) + rc = _NetworkManager->GetStunEndpoint(endPoint, port, bindTimeout, cacheTimeout); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["endPoint"] = endPoint; + response["port"] = port; + response["bindTimeout"] = bindTimeout; + response["cacheTimeout"] = cacheTimeout; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::SetStunEndpoint(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string endPoint = parameters["endPoint"].String(); + uint32_t port = parameters["port"].Number(); + uint32_t bindTimeout = parameters["bindTimeout"].Number(); + uint32_t cacheTimeout = parameters["cacheTimeout"].Number(); + + if (_NetworkManager) + rc = _NetworkManager->SetStunEndpoint(endPoint, port, bindTimeout, cacheTimeout); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetConnectivityTestEndpoints(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::IStringIterator* endpoints = NULL; + + + if (_NetworkManager) + rc = _NetworkManager->GetConnectivityTestEndpoints(endpoints); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + if (endpoints) + { + JsonArray array; + string endPoint{}; + while (endpoints->Next(endPoint) == true) + { + array.Add(endPoint); + } + endpoints->Release(); + response["endpoints"] = array; + response["success"] = true; + } + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::SetConnectivityTestEndpoints(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + ::WPEFramework::RPC::IIteratorType* endpointsIter{}; + JsonArray array = parameters["endpoints"].Array(); + + if (0 == array.Length() || 5 < array.Length()) + { + NMLOG_TRACE("minimum of 1 to maximum of 5 Urls are allowed"); + return rc; + } + + std::vector endpoints; + JsonArray::Iterator index(array.Elements()); + while (index.Next() == true) + { + if (Core::JSON::Variant::type::STRING == index.Current().Content()) + { + endpoints.push_back(index.Current().String().c_str()); + } + else + { + NMLOG_TRACE("Unexpected variant type"); + return rc; + } + } + endpointsIter = (Core::Service::Create(endpoints)); + + if (_NetworkManager) + rc = _NetworkManager->SetConnectivityTestEndpoints(endpointsIter); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + + if (endpointsIter) + endpointsIter->Release(); + + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::IsConnectedToInternet(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string ipversion = parameters["ipversion"].String(); + Exchange::INetworkManager::InternetStatus result; + + + if (_NetworkManager) + rc = _NetworkManager->IsConnectedToInternet(ipversion, result); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["isConnectedToInternet"] = (Exchange::INetworkManager::InternetStatus::INTERNET_FULLY_CONNECTED == result); + response["internetState"] = static_cast (result); + switch (result) + { + case Exchange::INetworkManager::InternetStatus::INTERNET_LIMITED: + response["status"] = string("LIMITED_INTERNET"); + break; + case Exchange::INetworkManager::InternetStatus::INTERNET_CAPTIVE_PORTAL: + response["status"] = string("CAPTIVE_PORTAL"); + break; + case Exchange::INetworkManager::InternetStatus::INTERNET_FULLY_CONNECTED: + response["status"] = string("FULLY_CONNECTED"); + // when fully connected to internet set Network subsystem + //setInternetSubsystem(); + break; + default: + response["status"] = string("NO_INTERNET"); + break; + } + + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetCaptivePortalURI(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string endPoint; + if (_NetworkManager) + rc = _NetworkManager->GetCaptivePortalURI(endPoint); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["uri"] = endPoint; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::StartConnectivityMonitoring(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + uint32_t interval = parameters["interval"].Number(); + + NMLOG_TRACE("connectivity interval = %d", interval); + if (_NetworkManager) + rc = _NetworkManager->StartConnectivityMonitoring(interval); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::StopConnectivityMonitoring(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + + if (_NetworkManager) + rc = _NetworkManager->StopConnectivityMonitoring(); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetPublicIP(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string ipAddress{}; + string ipversion = "IPv4"; + if (parameters.HasLabel("ipversion")) + ipversion = parameters["ipversion"].String(); + + if (_NetworkManager) + rc = _NetworkManager->GetPublicIP(ipversion, ipAddress); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["publicIP"] = ipAddress; + response["ipversion"] = ipversion; + response["success"] = true; + + /* TODO :: Cache this public IP Address */ + m_publicIPAddress = ipAddress; + m_publicIPAddressType = ipversion; + } + LOGTRACEMETHODFIN(); + return rc; + } + + void NetworkManager::PublishToThunderAboutInternet() + { + NMLOG_TRACE("No public IP persisted yet; Update the data"); + if (m_publicIPAddress.empty()) + { + JsonObject input, output; + GetPublicIP(input, output); + } + //TODO:: Report ISUBSYSTEM::Internet Ready. Get ISubsystem::Internet and if it is NULL, set it.. + } + + uint32_t NetworkManager::Ping(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + string result{}; + uint32_t rc = Core::ERROR_GENERAL; + if (parameters.HasLabel("endpoint")) + { + string endpoint{}; + string guid{}; + string ipversion{"IPv4"}; + uint32_t noOfRequest = 3; + uint16_t timeOutInSeconds = 5; + + endpoint = parameters["endpoint"].String(); + + if (parameters.HasLabel("ipversion")) + ipversion = parameters["ipversion"].String(); + + if (parameters.HasLabel("noOfRequest")) + noOfRequest = parameters["noOfRequest"].Number(); + + if (parameters.HasLabel("timeout")) + timeOutInSeconds = parameters["timeout"].Number(); + + if (parameters.HasLabel("guid")) + guid = parameters["guid"].String(); + + if (_NetworkManager) + rc = _NetworkManager->Ping(ipversion, endpoint, noOfRequest, timeOutInSeconds, guid, result); + else + rc = Core::ERROR_UNAVAILABLE; + } + + if (Core::ERROR_NONE == rc) + { + JsonObject reply; + reply.FromString(result); + reply["success"] = true; + response = reply; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::Trace(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string result{}; + const string ipversion = parameters["ipversion"].String(); + const string endpoint = parameters["endpoint"].String(); + const uint32_t noOfRequest = parameters["noOfRequest"].Number(); + const string guid = parameters["guid"].String(); + + if (_NetworkManager) + rc = _NetworkManager->Trace(ipversion, endpoint, noOfRequest, guid, result); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::StartWiFiScan(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + const Exchange::INetworkManager::WiFiFrequency frequency = static_cast (parameters["frequency"].Number()); + + if (_NetworkManager) + rc = _NetworkManager->StartWiFiScan(frequency); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::StopWiFiScan(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + + if (_NetworkManager) + rc = _NetworkManager->StopWiFiScan(); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetKnownSSIDs(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + + JsonArray ssids; + ::WPEFramework::RPC::IIteratorType* _ssids{}; + + if (_NetworkManager) + rc = _NetworkManager->GetKnownSSIDs(_ssids); + + if (Core::ERROR_NONE == rc) + { + ASSERT(_ssids != nullptr); + + if (_ssids != nullptr) + { + string _resultItem_{}; + while (_ssids->Next(_resultItem_) == true) + { + ssids.Add() = _resultItem_; + } + _ssids->Release(); + } + response["ssids"] = ssids; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::AddToKnownSSIDs(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::WiFiConnectTo ssid{}; + + if (parameters.HasLabel("ssid") && parameters.HasLabel("passphrase")) + { + ssid.m_ssid = parameters["ssid"].String(); + ssid.m_passphrase = parameters["passphrase"].String(); + ssid.m_securityMode = static_cast (parameters["securityMode"].Number()); + + if (_NetworkManager) + rc = _NetworkManager->AddToKnownSSIDs(ssid); + else + rc = Core::ERROR_UNAVAILABLE; + } + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::RemoveKnownSSID(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string ssid{}; + + if (parameters.HasLabel("ssid")) + { + ssid = parameters["ssid"].String(); + if (_NetworkManager) + rc = _NetworkManager->RemoveKnownSSID(ssid); + else + rc = Core::ERROR_UNAVAILABLE; + } + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::WiFiConnect(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::WiFiConnectTo ssid{}; + + if (parameters.HasLabel("ssid")) + ssid.m_ssid = parameters["ssid"].String(); + if (parameters.HasLabel("passphrase")) + ssid.m_passphrase = parameters["passphrase"].String(); + if (parameters.HasLabel("securityMode")) + ssid.m_securityMode = static_cast (parameters["securityMode"].Number()); + + if (_NetworkManager) + rc = _NetworkManager->WiFiConnect(ssid); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::WiFiDisconnect(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + + if (_NetworkManager) + rc = _NetworkManager->WiFiDisconnect(); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetConnectedSSID(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::WiFiSSIDInfo ssidInfo{}; + + if (_NetworkManager) + rc = _NetworkManager->GetConnectedSSID(ssidInfo); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["ssid"] = ssidInfo.m_ssid; + response["bssid"] = ssidInfo.m_bssid; + response["securityMode"] = static_cast (ssidInfo.m_securityMode); + response["signalStrength"] = ssidInfo.m_signalStrength; + response["frequency"] = static_cast (ssidInfo.m_frequency); + response["rate"] = ssidInfo.m_rate; + response["noise"] = ssidInfo.m_noise; + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::StartWPS(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string wps_pin{}; + Exchange::INetworkManager::WiFiWPS method; + + if (parameters.HasLabel("method")) + { + method = static_cast (parameters["method"].Number()); + } + else + method = Exchange::INetworkManager::WIFI_WPS_PBC; + + if ((Exchange::INetworkManager::WIFI_WPS_PIN == method) && parameters.HasLabel("wps_pin")) + { + wps_pin = parameters["wps_pin"].String(); + } + + if (_NetworkManager) + rc = _NetworkManager->StartWPS(method, wps_pin); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::StopWPS(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + + if (_NetworkManager) + rc = _NetworkManager->StopWPS(); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetWifiState(const JsonObject& parameters, JsonObject& response) + { + Exchange::INetworkManager::WiFiState state; + uint32_t rc = Core::ERROR_GENERAL; + + LOGINFOMETHOD(); + if (_NetworkManager) + rc = _NetworkManager->GetWifiState(state); + else + rc = Core::ERROR_UNAVAILABLE; + if (Core::ERROR_NONE == rc) + { + response["state"] = static_cast (state); + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetWiFiSignalStrength(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + string ssid{}; + string signalStrength{}; + Exchange::INetworkManager::WiFiSignalQuality quality; + + if (_NetworkManager) + rc = _NetworkManager->GetWiFiSignalStrength(ssid, signalStrength, quality); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["ssid"] = ssid; + response["signalStrength"] = signalStrength; + response["quality"] = static_cast (quality); + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::GetSupportedSecurityModes(const JsonObject& parameters, JsonObject& response) + { + LOGINFOMETHOD(); + uint32_t rc = Core::ERROR_GENERAL; + Exchange::INetworkManager::ISecurityModeIterator* securityModes{}; + + if (_NetworkManager) + rc = _NetworkManager->GetSupportedSecurityModes(securityModes); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + if (securityModes != nullptr) + { + JsonObject modes{}; + Exchange::INetworkManager::WIFISecurityModeInfo _resultItem_{}; + while (securityModes->Next(_resultItem_) == true) + { + response.Set(_resultItem_.m_securityModeText.c_str(), JsonValue(_resultItem_.m_securityMode)); + } + securityModes->Release(); + } + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + } +} diff --git a/NetworkManager/service/NetworkManagerLegacy.cpp b/NetworkManager/service/NetworkManagerLegacy.cpp new file mode 100644 index 0000000000..626b0c8858 --- /dev/null +++ b/NetworkManager/service/NetworkManagerLegacy.cpp @@ -0,0 +1,567 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2022 RDK Management +* +* 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 "NetworkManager.h" +#include "NetworkConnectivity.h" + +#define LOGINFOMETHOD() { std::string json; parameters.ToString(json); NMLOG_TRACE("Legacy params=%s", json.c_str() ); } +#define LOGTRACEMETHODFIN() { std::string json; response.ToString(json); NMLOG_TRACE("Legacy response=%s", json.c_str() ); } + +using namespace std; +using namespace WPEFramework::Plugin; + +namespace WPEFramework +{ + namespace Plugin + { + /** + * Hook up all our JSON RPC methods + * + * Each method definition comprises of: + * * Input parameters + * * Output parameters + * * Method name + * * Function that implements that method + */ + void NetworkManager::RegisterLegacyMethods() + { + Register("getInterfaces", &NetworkManager::getInterfaces, this); + Register("isInterfaceEnabled", &NetworkManager::isInterfaceEnabled, this); + Register("getPublicIP", &NetworkManager::getPublicIP, this); + Register("setInterfaceEnabled", &NetworkManager::setInterfaceEnabled, this); + Register("getDefaultInterface", &NetworkManager::getDefaultInterface, this); + Register("setDefaultInterface", &NetworkManager::setDefaultInterface, this); + Register("setIPSettings", &NetworkManager::setIPSettings, this); + Register("getIPSettings", &NetworkManager::getIPSettings, this); + Register("getInternetConnectionState", &NetworkManager::getInternetConnectionState, this); + Register("ping", &NetworkManager::ping, this); + Register("isConnectedToInternet", &NetworkManager::isConnectedToInternet, this); + Register("setConnectivityTestEndpoints", &NetworkManager::SetConnectivityTestEndpoints, this); + Register("startConnectivityMonitoring", &NetworkManager::StartConnectivityMonitoring, this); + Register("getCaptivePortalURI", &NetworkManager::GetCaptivePortalURI, this); + Register("stopConnectivityMonitoring", &NetworkManager::StopConnectivityMonitoring, this); + Register("cancelWPSPairing", &NetworkManager::StopWPS, this); + Register("clearSSID", &NetworkManager::clearSSID, this); + Register("connect", &NetworkManager::WiFiConnect, this); + Register("disconnect", &NetworkManager::WiFiDisconnect, this); + Register("getConnectedSSID", &NetworkManager::getConnectedSSID, this); + Register("startScan", &NetworkManager::StartWiFiScan, this); + Register("stopScan", &NetworkManager::StopWiFiScan, this); + Register("getPairedSSID", &NetworkManager::GetKnownSSIDs, this); + Register("getPairedSSIDInfo", &NetworkManager::GetConnectedSSID, this); + Register("initiateWPSPairing", &NetworkManager::initiateWPSPairing, this); + Register("isPaired", &NetworkManager::isPaired, this); + Register("saveSSID", &NetworkManager::AddToKnownSSIDs, this); + Register("getSupportedSecurityModes", &NetworkManager::GetSupportedSecurityModes, this); + Register("getCurrentState", &NetworkManager::GetWifiState, this); + } + + /** + * Unregister all our JSON-RPC methods + */ + void NetworkManager::UnregisterLegacyMethods() + { + Unregister("getInterfaces"); + Unregister("isInterfaceEnabled"); + Unregister("getPublicIP"); + Unregister("setInterfaceEnabled"); + Unregister("getDefaultInterface"); + Unregister("setDefaultInterface"); + Unregister("setIPSettings"); + Unregister("getIPSettings"); + Unregister("getInternetConnectionState"); + Unregister("ping"); + Unregister("isConnectedToInternet"); + Unregister("setConnectivityTestEndpoints"); + Unregister("startConnectivityMonitoring"); + Unregister("getCaptivePortalURI"); + Unregister("stopConnectivityMonitoring"); + Unregister("cancelWPSPairing"); + Unregister("clearSSID"); + Unregister("connect"); + Unregister("disconnect"); + Unregister("getConnectedSSID"); + Unregister("startScan"); + Unregister("stopScan"); + Unregister("getPairedSSID"); + Unregister("getPairedSSIDInfo"); + Unregister("initiateWPSPairing"); + Unregister("isPaired"); + Unregister("saveSSID"); + Unregister("getSupportedSecurityModes"); + Unregister("getCurrentState"); + } + +#define CIDR_NETMASK_IP_LEN 32 +const string CIDR_PREFIXES[CIDR_NETMASK_IP_LEN] = { + "128.0.0.0", + "192.0.0.0", + "224.0.0.0", + "240.0.0.0", + "248.0.0.0", + "252.0.0.0", + "254.0.0.0", + "255.0.0.0", + "255.128.0.0", + "255.192.0.0", + "255.224.0.0", + "255.240.0.0", + "255.248.0.0", + "255.252.0.0", + "255.254.0.0", + "255.255.0.0", + "255.255.128.0", + "255.255.192.0", + "255.255.224.0", + "255.255.240.0", + "255.255.248.0", + "255.255.252.0", + "255.255.254.0", + "255.255.255.0", + "255.255.255.128", + "255.255.255.192", + "255.255.255.224", + "255.255.255.240", + "255.255.255.248", + "255.255.255.252", + "255.255.255.254", + "255.255.255.255", + }; + + uint32_t NetworkManager::getInterfaces (const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpResponse; + JsonArray array; + + LOGINFOMETHOD(); + rc = GetAvailableInterfaces(parameters, tmpResponse); + + const JsonArray& tmpArray = tmpResponse["interfaces"].Array(); + for (int i=0; iStartWPS(wpsmethod, wps_pin); + else + rc = Core::ERROR_UNAVAILABLE; + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::getDefaultInterface (const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpResponse; + + LOGINFOMETHOD(); + rc = GetPrimaryInterface(parameters, tmpResponse); + + if (Core::ERROR_NONE == rc) + { + if ("wlan0" == tmpResponse["interface"].String()) + response["interface"] = "WIFI"; + else if("eth0" == tmpResponse["interface"].String()) + response["interface"] = "ETHERNET"; + response["success"] = tmpResponse["success"]; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::setDefaultInterface(const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpParameters; + string interface; + LOGINFOMETHOD(); + if("WIFI" == parameters["interface"].String()) + tmpParameters["interface"] = "wlan0"; + else if("ETHERNET" == parameters["interface"].String()) + tmpParameters["interface"] = "eth0"; + + rc = SetPrimaryInterface(tmpParameters, response); + LOGTRACEMETHODFIN(); + + return rc; + } + uint32_t NetworkManager::setIPSettings(const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpResponse; + JsonObject tmpParameters; + Exchange::INetworkManager::IPAddressInfo result{}; + + LOGINFOMETHOD(); + + if("WIFI" == parameters["interface"].String()) + tmpParameters["interface"] = "wlan0"; + else if("ETHERNET" == parameters["interface"].String()) + tmpParameters["interface"] = "eth0"; + + tmpParameters["ipversion"] = parameters["ipversion"]; + tmpParameters["autoconfig"] = parameters["autoconfig"]; + tmpParameters["ipaddress"] = parameters["ipaddr"]; + auto it = std::find(std::begin(CIDR_PREFIXES), std::end(CIDR_PREFIXES), parameters["netmask"].String()); + if (it == std::end(CIDR_PREFIXES)) + return rc; + else + tmpParameters["prefix"] = std::distance(std::begin(CIDR_PREFIXES), it); + tmpParameters["gateway"] = parameters["gateway"]; + tmpParameters["primarydns"] = parameters["primarydns"]; + tmpParameters["secondarydns"] = parameters["secondarydns"]; + + rc = SetIPSettings(tmpParameters, tmpResponse); + + if (Core::ERROR_NONE == rc) + { + response["supported"] = true; + response["success"] = tmpResponse["success"]; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::getIPSettings (const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpResponse; + JsonObject tmpParameters; + size_t index; + + LOGINFOMETHOD(); + + if (parameters.HasLabel("ipversion")) + tmpParameters["ipversion"] = parameters["ipversion"]; + if (parameters.HasLabel("interface")) + { + if ("WIFI" == parameters["interface"].String()) + tmpParameters["interface"] = "wlan0"; + else if("ETHERNET" == parameters["interface"].String()) + tmpParameters["interface"] = "eth0"; + } + + rc = GetIPSettings(tmpParameters, tmpResponse); + + if (Core::ERROR_NONE == rc) + { + index = tmpResponse["prefix"].Number(); + if(CIDR_NETMASK_IP_LEN <= index) + return Core::ERROR_GENERAL; + else + response["netmask"] = CIDR_PREFIXES[index]; + if (parameters.HasLabel("interface")) + { + response["interface"] = parameters["interface"]; + } + else + { + if ("wlan0" == m_defaultInterface) + response["interface"] = "WIFI"; + else if("eth0" == m_defaultInterface) + response["interface"] = "ETHERNET"; + } + response["ipversion"] = tmpResponse["ipversion"]; + response["autoconfig"] = tmpResponse["autoconfig"]; + response["dhcpserver"] = tmpResponse["dhcpserver"]; + response["ipaddr"] = tmpResponse["ipaddress"]; + response["gateway"] = tmpResponse["gateway"]; + response["primarydns"] = tmpResponse["primarydns"]; + response["secondarydns"] = tmpResponse["secondarydns"]; + response["success"] = tmpResponse["success"]; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::isConnectedToInternet(const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpResponse; + + LOGINFOMETHOD(); + string ipversion = parameters["ipversion"].String(); + rc = IsConnectedToInternet(parameters, tmpResponse); + + if (Core::ERROR_NONE == rc) + { + response["connectedToInternet"] = tmpResponse["isConnectedToInternet"]; + if(ipversion == "IPV4" || ipversion == "IPV6") + response["ipversion"] = ipversion.c_str(); + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::getInternetConnectionState(const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + uint32_t rc1 = Core::ERROR_GENERAL; + string endPoint; + JsonObject tmpResponse; + JsonObject captivePortalResponse; + JsonObject tmpParameters; + string status; + + LOGINFOMETHOD(); + string ipversion = parameters["ipversion"].String(); + rc = IsConnectedToInternet(parameters, tmpResponse); + if (Core::ERROR_NONE == rc) + { + status = tmpResponse["status"].String(); + NMLOG_TRACE("status = %s\n", status ); + NMLOG_TRACE("tmpResponse[status].String() = %s\n", tmpResponse["status"].String() ); + if(status == "LIMITED_INTERNET") + response["state"] = static_cast(nsm_internetState::LIMITED_INTERNET); + else if(status == "CAPTIVE_PORTAL") + { + response["state"] = static_cast(nsm_internetState::CAPTIVE_PORTAL); + rc1 = getCaptivePortalURI(tmpParameters, captivePortalResponse); + if (Core::ERROR_NONE == rc1) + response["uri"] = captivePortalResponse["uri"]; + } + else if(status == "FULLY_CONNECTED") + response["state"] = static_cast(nsm_internetState::FULLY_CONNECTED); + else + response["state"] = static_cast(nsm_internetState::NO_INTERNET); + + if(ipversion == "IPV4" || ipversion == "IPV6") + response["ipversion"] = ipversion.c_str(); + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::ping(const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + struct in_addr ipv4address; + struct in6_addr ipv6address; + JsonObject tmpParameters; + JsonObject tmpResponse; + string endpoint{}; + + LOGINFOMETHOD(); + + endpoint = parameters["endpoint"].String(); + + if (inet_pton(AF_INET, endpoint.c_str(), &ipv4address) > 0) + tmpParameters["ipversion"] = "IPv4"; + else if (inet_pton(AF_INET6, endpoint.c_str(), &ipv6address) > 0) + tmpParameters["ipversion"] = "IPv6"; + + tmpParameters["noOfRequest"] = parameters["packets"]; + tmpParameters["endpoint"] = parameters["endpoint"]; + tmpParameters["timeout"] = 5; + tmpParameters["guid"] = parameters["guid"]; + + rc = Ping(tmpParameters, response); + + if (Core::ERROR_NONE == rc) + { + response["success"] = true; + } + LOGTRACEMETHODFIN(); + return rc; + } + uint32_t NetworkManager::getPublicIP(const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + string interface; + string ipversion{"IPv4"}; + JsonObject tmpParameters; + JsonObject tmpResponse; + + LOGINFOMETHOD(); + if("WIFI" == parameters["iface"].String()) + interface = "wlan0"; + else if("ETHERNET" == parameters["iface"].String()) + interface = "eth0"; + + if(parameters["ipv6"].Boolean()) + ipversion = "IPv6"; + else + ipversion = "IPv4"; + + tmpParameters["interface"] = interface; + tmpParameters["ipversion"] = ipversion; + rc = GetPublicIP(tmpParameters, tmpResponse); + + if (Core::ERROR_NONE == rc) + { + response["public_ip"] = tmpResponse["publicIP"]; + response["success"] = tmpResponse["success"]; + } + LOGTRACEMETHODFIN(); + return rc; + } + + uint32_t NetworkManager::isInterfaceEnabled (const JsonObject& parameters, JsonObject& response) + { + uint32_t rc = Core::ERROR_GENERAL; + JsonObject tmpResponse; + + LOGINFOMETHOD(); + rc = GetAvailableInterfaces(parameters, tmpResponse); + + const JsonArray& tmpArray = tmpResponse["interfaces"].Array(); + for (int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_RDK_LOGGER +#include "rdk_debug.h" +#endif + +namespace NetworkManagerLogger { + static LogLevel gDefaultLogLevel = TRACE_LEVEL; + + static inline void sync_stdout() + { + if (getenv("SYNC_STDOUT")) + setvbuf(stdout, NULL, _IOLBF, 0); + } + + const char* methodName(const std::string& prettyFunction) + { + size_t colons = prettyFunction.find("::"); + size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1; + size_t end = prettyFunction.rfind("(") - begin; + + return prettyFunction.substr(begin,end).c_str(); + } + + void Init() + { + sync_stdout(); +#ifdef USE_RDK_LOGGER + rdk_logger_init(0 == access("/opt/debug.ini", R_OK) ? "/opt/debug.ini" : "/etc/debug.ini"); +#endif + } + + void logPrint(LogLevel level, const char* file, const char* func, int line, const char* format, ...) + { + size_t n = 0; + const short kFormatMessageSize = 1024; + char formattedLog[kFormatMessageSize] = {0}; + + va_list args; + + va_start(args, format); + n = vsnprintf(formattedLog, (kFormatMessageSize - 1), format, args); + va_end(args); + + if (n > (kFormatMessageSize - 1)) + { + formattedLog[kFormatMessageSize - 4] = '.'; + formattedLog[kFormatMessageSize - 3] = '.'; + formattedLog[kFormatMessageSize - 2] = '.'; + } + formattedLog[kFormatMessageSize - 1] = '\0'; +#ifdef USE_RDK_LOGGER + RDK_LOG((int)level, "LOG.RDK.NETSRVMGER", "%s\n", formattedLog); +#else + const char* levelMap[] = {"Fatal", "Error", "Warning", "Info", "Verbose", "Trace"}; + struct timeval tv; + struct tm* lt; + + if (gDefaultLogLevel < level) + return; + + gettimeofday(&tv, NULL); + lt = localtime(&tv.tv_sec); + + printf("%.2d:%.2d:%.2d.%.6lld %-10s %s %s:%d : %s\n", lt->tm_hour, lt->tm_min, lt->tm_sec, (long long int)tv.tv_usec, levelMap[level], basename(file), func, line, formattedLog); + fflush(stdout); +#endif + } + + void SetLevel(LogLevel level) + { + gDefaultLogLevel = level; + NMLOG_INFO("NetworkManager logLevel:%d", level); +#ifdef USE_RDK_LOGGER + // TODO : Inform RDKLogger to change the log level +#endif + } +} // namespace NetworkManagerLogger diff --git a/NetworkManager/service/NetworkManagerLogger.h b/NetworkManager/service/NetworkManagerLogger.h new file mode 100644 index 0000000000..3b8b173997 --- /dev/null +++ b/NetworkManager/service/NetworkManagerLogger.h @@ -0,0 +1,68 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * 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. + */ + +#ifndef NM_LOGGER_H +#define NM_LOGGER_H + +#include +#include +#include +#include +#include +#include +#include "Module.h" + +namespace NetworkManagerLogger { +/** + * Logging level with an increasing order of refinement + * (TRACE_LEVEL = Finest logging) + * It is essental to start with 0 and increase w/o gaps as the value + * can be used for indexing in a mapping table. + */ +enum LogLevel {FATAL_LEVEL = 0, ERROR_LEVEL, WARNING_LEVEL, INFO_LEVEL, VERBOSE_LEVEL, TRACE_LEVEL}; + +/** + * @brief Init logging + * Should be called once per program run before calling log-functions + */ +void Init(); + +/** + * @brief To set log level while runtime + */ +void SetLevel(LogLevel level); + +/** + * @brief Log a message + * The function is defined by logging backend. + * Currently 2 variants are supported: RDKLOGGER & stdout(default) + */ +void logPrint(LogLevel level, const char* file, const char* func, int line, const char* format, ...) __attribute__ ((format (printf, 5, 6))); + + +#define NMLOG_TRACE(FMT, ...) logPrint(NetworkManagerLogger::TRACE_LEVEL, __FILE__, __func__, __LINE__, FMT, ##__VA_ARGS__) +#define NMLOG_VERBOSE(FMT, ...) logPrint(NetworkManagerLogger::VERBOSE_LEVEL, __FILE__, __func__, __LINE__, FMT, ##__VA_ARGS__) +#define NMLOG_INFO(FMT, ...) logPrint(NetworkManagerLogger::INFO_LEVEL, __FILE__, __func__, __LINE__, FMT, ##__VA_ARGS__) +#define NMLOG_WARNING(FMT, ...) logPrint(NetworkManagerLogger::WARNING_LEVEL, __FILE__, __func__, __LINE__, FMT, ##__VA_ARGS__) +#define NMLOG_ERROR(FMT, ...) logPrint(NetworkManagerLogger::ERROR_LEVEL, __FILE__, __func__, __LINE__, FMT, ##__VA_ARGS__) +#define NMLOG_FATAL(FMT, ...) logPrint(NetworkManagerLogger::FATAL_LEVEL, __FILE__,__func__, __LINE__, FMT, ##__VA_ARGS__) + +} // namespace NetworkManagerLogger + +#endif // NM_LOGGER_H diff --git a/NetworkManager/service/NetworkManagerPlugin.json b/NetworkManager/service/NetworkManagerPlugin.json new file mode 100644 index 0000000000..388367f4bf --- /dev/null +++ b/NetworkManager/service/NetworkManagerPlugin.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://raw.githubusercontent.com/rdkcentral/rdkservices/main/Tools/json_generator/schemas/plugin.schema.json", + "info": { + "title": "NetworkManager Plugin", + "class": "NetworkManager", + "callsign": "org.rdk.NetworkManager", + "locator": "libWPEFrameworkNetworkManager.so", + "status": "production", + "description": "A Unified `NetworkManager` plugin that allows you to manage Ethernet and Wifi interfaces on the device.", + "version": "0.1.0" + }, + "interface": { + "$ref": "NetworkManager.json#" + } +} diff --git a/NetworkManager/service/NetworkManagerRDKProxy.cpp b/NetworkManager/service/NetworkManagerRDKProxy.cpp new file mode 100644 index 0000000000..23780bfb26 --- /dev/null +++ b/NetworkManager/service/NetworkManagerRDKProxy.cpp @@ -0,0 +1,1194 @@ +#include "NetworkManagerImplementation.h" +#include "WifiSignalStrengthMonitor.h" +#include "libIBus.h" + +using namespace WPEFramework; +using namespace WPEFramework::Plugin; +using namespace std; + +namespace WPEC = WPEFramework::Core; +namespace WPEJ = WPEFramework::Core::JSON; + +#define IARM_BUS_NM_SRV_MGR_NAME "NET_SRV_MGR" + +#define MAX_IP_ADDRESS_LEN 46 +#define NETSRVMGR_INTERFACES_MAX 16 +#define MAX_ENDPOINTS 5 +#define MAX_ENDPOINT_SIZE 512 +#define MAX_URI_LEN 512 +#define MAX_HOST_NAME_LEN 128 +#define DEFAULT_PING_PACKETS 15 +#define CIDR_NETMASK_IP_LEN 32 +#define INTERFACE_SIZE 10 +#define INTERFACE_LIST 50 +#define MAX_IP_FAMILY_SIZE 10 + + +#define BUFF_LENGTH_64 65 +#define BUFF_LENGTH_256 257 +#define BUFF_MAX 1025 +#define BUFF_MAC 18 +#define BUFF_MIN 17 +#define BUFF_LENGTH_4 4 +#define SSID_SIZE 33 +#define BSSID_BUFF 20 +#define BUFF_LENGTH_24 24 +#define PASSPHRASE_BUFF 385 +#define MAX_SSIDLIST_BUF (48*1024) +#define MAX_FILE_PATH_LEN 4096 + + +typedef enum _NetworkManager_EventId_t { + IARM_BUS_NETWORK_MANAGER_EVENT_SET_INTERFACE_ENABLED=50, + IARM_BUS_NETWORK_MANAGER_EVENT_SET_INTERFACE_CONTROL_PERSISTENCE, + IARM_BUS_NETWORK_MANAGER_EVENT_WIFI_INTERFACE_STATE, + IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_ENABLED_STATUS, + IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_CONNECTION_STATUS, + IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_IPADDRESS, + IARM_BUS_NETWORK_MANAGER_EVENT_DEFAULT_INTERFACE, + IARM_BUS_NETWORK_MANAGER_EVENT_INTERNET_CONNECTION_CHANGED, + IARM_BUS_NETWORK_MANAGER_MAX, +} IARM_Bus_NetworkManager_EventId_t; + +typedef enum _IARM_Bus_NMgr_WiFi_EventId_t { + IARM_BUS_WIFI_MGR_EVENT_onWIFIStateChanged = 1, + IARM_BUS_WIFI_MGR_EVENT_onError, + IARM_BUS_WIFI_MGR_EVENT_onSSIDsChanged, + IARM_BUS_WIFI_MGR_EVENT_onAvailableSSIDs, + IARM_BUS_WIFI_MGR_EVENT_onAvailableSSIDsIncr, + IARM_BUS_WIFI_MGR_EVENT_onWIFILNFStateChanged, + IARM_BUS_WIFI_MGR_EVENT_MAX, /*!< Maximum event id*/ +} IARM_Bus_NMgr_WiFi_EventId_t; + + +typedef struct { + char name[16]; + char mac[20]; + unsigned int flags; +} NetSrvMgr_Interface_t; + +typedef struct { + unsigned char size; + NetSrvMgr_Interface_t interfaces[NETSRVMGR_INTERFACES_MAX]; +} IARM_BUS_NetSrvMgr_InterfaceList_t; + +typedef enum _NetworkManager_GetIPSettings_ErrorCode_t +{ + NETWORK_IPADDRESS_ACQUIRED, + NETWORK_IPADDRESS_NOTFOUND, + NETWORK_NO_ROUTE_INTERFACE, + NETWORK_NO_DEFAULT_ROUTE, + NETWORK_DNS_NOT_CONFIGURED, + NETWORK_INVALID_IPADDRESS, +} NetworkManager_GetIPSettings_ErrorCode_t; + +typedef struct { + char interface[16]; + char ipversion[16]; + bool autoconfig; + char ipaddress[MAX_IP_ADDRESS_LEN]; + char netmask[MAX_IP_ADDRESS_LEN]; + char gateway[MAX_IP_ADDRESS_LEN]; + char dhcpserver[MAX_IP_ADDRESS_LEN]; + char primarydns[MAX_IP_ADDRESS_LEN]; + char secondarydns[MAX_IP_ADDRESS_LEN]; + bool isSupported; + NetworkManager_GetIPSettings_ErrorCode_t errCode; +} IARM_BUS_NetSrvMgr_Iface_Settings_t; + +typedef struct { + char interface[16]; + char gateway[MAX_IP_ADDRESS_LEN]; +} IARM_BUS_NetSrvMgr_DefaultRoute_t; + +typedef struct { + char interface[16]; + bool status; +} IARM_BUS_NetSrvMgr_Iface_EventInterfaceStatus_t; + +typedef IARM_BUS_NetSrvMgr_Iface_EventInterfaceStatus_t IARM_BUS_NetSrvMgr_Iface_EventInterfaceEnabledStatus_t; +typedef IARM_BUS_NetSrvMgr_Iface_EventInterfaceStatus_t IARM_BUS_NetSrvMgr_Iface_EventInterfaceConnectionStatus_t; + +typedef struct { + char interface[16]; + char ip_address[MAX_IP_ADDRESS_LEN]; + bool is_ipv6; + bool acquired; +} IARM_BUS_NetSrvMgr_Iface_EventInterfaceIPAddress_t; + +typedef struct { + char oldInterface[16]; + char newInterface[16]; +} IARM_BUS_NetSrvMgr_Iface_EventDefaultInterface_t; + +typedef struct +{ + char server[MAX_HOST_NAME_LEN]; + uint16_t port; + bool ipv6; + char interface[16]; + uint16_t bind_timeout; + uint16_t cache_timeout; + bool sync; + char public_ip[MAX_IP_ADDRESS_LEN]; +} IARM_BUS_NetSrvMgr_Iface_StunRequest_t; + +typedef struct +{ + bool disableConnectivityTest; +} IARM_BUS_NetSrvMgr_configurePNI_t; + + + +/*! Supported values are NONE - 0, WPA - 1, WEP - 2*/ +typedef enum _SsidSecurity +{ + NET_WIFI_SECURITY_NONE = 0, + NET_WIFI_SECURITY_WEP_64, + NET_WIFI_SECURITY_WEP_128, + NET_WIFI_SECURITY_WPA_PSK_TKIP, + NET_WIFI_SECURITY_WPA_PSK_AES, + NET_WIFI_SECURITY_WPA2_PSK_TKIP, + NET_WIFI_SECURITY_WPA2_PSK_AES, + NET_WIFI_SECURITY_WPA_ENTERPRISE_TKIP, + NET_WIFI_SECURITY_WPA_ENTERPRISE_AES, + NET_WIFI_SECURITY_WPA2_ENTERPRISE_TKIP, + NET_WIFI_SECURITY_WPA2_ENTERPRISE_AES, + NET_WIFI_SECURITY_WPA_WPA2_PSK, + NET_WIFI_SECURITY_WPA_WPA2_ENTERPRISE, + NET_WIFI_SECURITY_WPA3_PSK_AES, + NET_WIFI_SECURITY_WPA3_SAE, + NET_WIFI_SECURITY_NOT_SUPPORTED = 99, +} SsidSecurity; + + +/*! Event states associated with WiFi connection */ +typedef enum _WiFiStatusCode_t { + WIFI_UNINSTALLED, /**< The device was in an installed state, and was uninstalled */ + WIFI_DISABLED, /**< The device is installed (or was just installed) and has not yet been enabled */ + WIFI_DISCONNECTED, /**< The device is not connected to a network */ + WIFI_PAIRING, /**< The device is not connected to a network, but not yet connecting to a network */ + WIFI_CONNECTING, /**< The device is attempting to connect to a network */ + WIFI_CONNECTED, /**< The device is successfully connected to a network */ + WIFI_FAILED /**< The device has encountered an unrecoverable error with the wifi adapter */ +} WiFiStatusCode_t; + +/*! Error code: A recoverable, unexpected error occurred, + * as defined by one of the following values */ +typedef enum _WiFiErrorCode_t { + WIFI_SSID_CHANGED, /**< The SSID of the network changed */ + WIFI_CONNECTION_LOST, /**< The connection to the network was lost */ + WIFI_CONNECTION_FAILED, /**< The connection failed for an unknown reason */ + WIFI_CONNECTION_INTERRUPTED, /**< The connection was interrupted */ + WIFI_INVALID_CREDENTIALS, /**< The connection failed due to invalid credentials */ + WIFI_NO_SSID, /**< The SSID does not exist */ + WIFI_UNKNOWN, /**< Any other error */ + WIFI_AUTH_FAILED /**< The connection failed due to auth failure */ +} WiFiErrorCode_t; + +typedef enum _WiFiLNFState_t { + LNF_SSID_CONNECTED, /**< Connected to the LNF network */ + LNF_SSID_CONNECT_FAILED, /**< failed connect to the LNF network */ + LNF_ENDPOINT_BACKOFF_TIME, /**< lnf in last requested backoff time */ + LNF_ENDPOINT_CONNECTED, /**< lnf connected to end point and get the LFAT */ + LNF_RECEIVED_PRIVATE_SSID_INFO, /**< lnf process Got private cridential*/ + LNF_SWITCHING_TO_PRIVATE, /**< lnf connected to private*/ + LNF_SSID_DISCONNECTED, /**< disconnected form lnf ssid */ + LNF_ERROR /**< common lnf error replay from lnf library */ +} WiFiLNFState_t; + +typedef struct _IARM_Bus_WiFiSrvMgr_WPS_Parameters_t +{ + bool pbc; + char pin[9]; + bool status; +} IARM_Bus_WiFiSrvMgr_WPS_Parameters_t; + + +/*! LNF states */ +typedef enum _WiFiLNFStatusCode_t { + LNF_UNITIALIZED, /**< Network manager hasn't started the LNF process */ + LNF_IN_PROGRESS, /**< Network manager has started LNF, and waiting for operation to complete */ + CONNECTED_LNF, /**< Connected to the LNF network */ + CONNECTED_PRIVATE, /** Connected to a network that is not LNF */ + DISCONNECTED_NO_LNF_GATEWAY_DETECTED, /**< unable to connect to LNF network */ + DISCONNECTED_GET_LFAT_FAILED, /**< client wasn't able to acquire an LFAT */ + DISCONNECTED_CANT_CONNECT_TO_PRIVATE // client could obtain LFAT, but couldn't connect to private network */ + /**< The device has encountered an unrecoverable error with the wifi adapter */ +} WiFiLNFStatusCode_t; + + +typedef struct _setWiFiAdapter +{ + bool enable; +} setWiFiAdapter; + +typedef struct _WiFiConnection +{ + char ssid[SSID_SIZE]; + char bssid[BSSID_BUFF]; + char security[BUFF_LENGTH_64]; + char passphrase[PASSPHRASE_BUFF]; + SsidSecurity security_mode; + char security_WEPKey[PASSPHRASE_BUFF]; + char security_PSK[PASSPHRASE_BUFF]; + char eapIdentity[BUFF_LENGTH_256]; + char carootcert[MAX_FILE_PATH_LEN]; + char clientcert[MAX_FILE_PATH_LEN]; + char privatekey[MAX_FILE_PATH_LEN]; +} WiFiConnection; + +typedef struct _WiFiConnectedSSIDInfo +{ + char ssid[SSID_SIZE]; /**< The name of connected SSID. */ + char bssid[BSSID_BUFF]; /**< The the Basic Service Set ID (mac address). */ + char band[BUFF_MIN]; /**< The frequency band at which the client is conneted to. */ + int securityMode; /**< Current WiFi Security Mode used for connection. */ + int frequency; /**< The Frequency wt which the client is connected to. */ + float rate; /**< The Physical data rate in Mbps */ + float noise; /**< The average noise strength in dBm. */ + float signalStrength; /**< The RSSI value in dBm. */ + +} WiFiConnectedSSIDInfo_t; + +typedef struct _WiFiPairedSSIDInfo +{ + char ssid[SSID_SIZE]; /**< The name of connected SSID. */ + char bssid[BSSID_BUFF]; /**< The the Basic Service Set ID (mac address). */ + char security[BUFF_LENGTH_64]; /**< security of AP */ + SsidSecurity secMode; +} WiFiPairedSSIDInfo_t; + + +typedef enum _WiFiConnectionTypeCode_t { + WIFI_CON_UNKNOWN, + WIFI_CON_WPS, + WIFI_CON_MANUAL, + WIFI_CON_LNF, + WIFI_CON_PRIVATE, + WIFI_CON_MAX, +} WiFiConnectionTypeCode_t; + + +typedef struct _IARM_Bus_WiFiSrvMgr_Param_t { + union { + WiFiLNFStatusCode_t wifiLNFStatus; + WiFiStatusCode_t wifiStatus; + setWiFiAdapter setwifiadapter; + WiFiConnection connect; + WiFiConnection saveSSID; + WiFiConnection clearSSID; + WiFiConnectedSSIDInfo_t getConnectedSSID; + WiFiPairedSSIDInfo_t getPairedSSIDInfo; + WiFiConnectionTypeCode_t connectionType; + struct getPairedSSID { + char ssid[SSID_SIZE]; + } getPairedSSID; + bool isPaired; + } data; + bool status; +} IARM_Bus_WiFiSrvMgr_Param_t; + +typedef struct _IARM_BUS_NetSrvMgr_Iface_EventData_t { + union { + char activeIface[INTERFACE_SIZE]; + char allNetworkInterfaces[INTERFACE_LIST]; + char setInterface[INTERFACE_SIZE]; + char activeIfaceIpaddr[MAX_IP_ADDRESS_LEN]; + }; + char interfaceCount; + bool isInterfaceEnabled; + bool persist; + char ipfamily[MAX_IP_FAMILY_SIZE]; +} IARM_BUS_NetSrvMgr_Iface_EventData_t; + +typedef struct _IARM_BUS_WiFiSrvMgr_EventData_t { + union { + struct _WIFI_STATECHANGE_DATA { + WiFiStatusCode_t state; + } wifiStateChange; + struct _WIFI_ERROR { + WiFiErrorCode_t code; + } wifiError; + struct _WIFI_SSID_LIST { + char ssid_list[MAX_SSIDLIST_BUF]; + bool more_data; + } wifiSSIDList; + struct _WIFI_LNF_STATE { + WiFiLNFState_t state; + float backOffTime; + }wifilnfState; + } data; +} IARM_BUS_WiFiSrvMgr_EventData_t; + +typedef struct _wifiSsidData_t { + char jdata[MAX_SSIDLIST_BUF]; /**< Buffer containing the serialized data. */ + size_t jdataLen; /**< Length of the data buffer. */ +} wifiSsidData_t; + +typedef struct _IARM_Bus_WiFiSrvMgr_SsidList_Param_t { + wifiSsidData_t curSsids; + bool status; +} IARM_Bus_WiFiSrvMgr_SsidList_Param_t; + + +#define IARM_BUS_NETSRVMGR_API_getInterfaceList "getInterfaceList" +#define IARM_BUS_NETSRVMGR_API_getDefaultInterface "getDefaultInterface" +#define IARM_BUS_NETSRVMGR_API_setDefaultInterface "setDefaultInterface" +#define IARM_BUS_NETSRVMGR_API_isInterfaceEnabled "isInterfaceEnabled" +#define IARM_BUS_NETSRVMGR_API_setInterfaceEnabled "setInterfaceEnabled" +#define IARM_BUS_NETSRVMGR_API_setIPSettings "setIPSettings" +#define IARM_BUS_NETSRVMGR_API_getIPSettings "getIPSettings" +#define IARM_BUS_NETSRVMGR_API_isAvailable "isAvailable" +#define IARM_BUS_WIFI_MGR_API_getAvailableSSIDsAsync "getAvailableSSIDsAsync" /**< Retrieve array of strings representing SSIDs */ +#define IARM_BUS_WIFI_MGR_API_getAvailableSSIDsAsyncIncr "getAvailableSSIDsAsyncIncr" /**< Retrieve array of strings representing SSIDs in an incremental way */ +#define IARM_BUS_WIFI_MGR_API_stopProgressiveWifiScanning "stopProgressiveWifiScanning" /**< Stop any in-progress wifi progressive scanning thread */ +#define IARM_BUS_WIFI_MGR_API_initiateWPSPairing2 "initiateWPSPairing2" /**< Initiate connection via WPS via either Push Button or PIN */ +#define IARM_BUS_WIFI_MGR_API_cancelWPSPairing "cancelWPSPairing" /**< Cancel in-progress WPS */ +#define IARM_BUS_WIFI_MGR_API_getConnectedSSID "getConnectedSSID" /**< Return properties of the currently connected SSID */ +#define IARM_BUS_WIFI_MGR_API_saveSSID "saveSSID" /**< Save SSID and passphrase */ +#define IARM_BUS_WIFI_MGR_API_clearSSID "clearSSID" /**< Clear given SSID */ +#define IARM_BUS_WIFI_MGR_API_connect "connect" /**< Connect with given or saved SSID and passphrase */ +#define IARM_BUS_WIFI_MGR_API_disconnectSSID "disconnectSSID" /**< Disconnect from current SSID */ +#define IARM_BUS_WIFI_MGR_API_getCurrentState "getCurrentState" /**< Retrieve current state */ + + +namespace WPEFramework +{ + namespace Plugin + { + const float signalStrengthThresholdExcellent = -50.0f; + const float signalStrengthThresholdGood = -60.0f; + const float signalStrengthThresholdFair = -67.0f; + NetworkManagerImplementation* _instance = nullptr; + + Exchange::INetworkManager::WiFiState to_wifi_state(WiFiStatusCode_t code) { + switch (code) + { + case WIFI_DISCONNECTED: + return Exchange::INetworkManager::WIFI_STATE_DISCONNECTED; + case WIFI_PAIRING: + return Exchange::INetworkManager::WIFI_STATE_PAIRING; + case WIFI_CONNECTING: + return Exchange::INetworkManager::WIFI_STATE_CONNECTING; + case WIFI_CONNECTED: + return Exchange::INetworkManager::WIFI_STATE_CONNECTED; + case WIFI_FAILED: + return Exchange::INetworkManager::WIFI_STATE_CONNECTION_FAILED; + case WIFI_UNINSTALLED: + return Exchange::INetworkManager::WIFI_STATE_UNINSTALLED; + case WIFI_DISABLED: + return Exchange::INetworkManager::WIFI_STATE_DISABLED; + } + return Exchange::INetworkManager::WIFI_STATE_CONNECTION_FAILED; + } + + void NetworkManagerInternalEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len) + { + LOG_ENTRY_FUNCTION(); + if (_instance) + { + // ::_instance->Event(); + if (strcmp(owner, IARM_BUS_NM_SRV_MGR_NAME) != 0) + { + NMLOG_ERROR("ERROR - unexpected event: owner %s, eventId: %d, data: %p, size: %d.", owner, (int)eventId, data, (int)len); + return; + } + if (data == nullptr || len == 0) + { + NMLOG_ERROR("ERROR - event with NO DATA: eventId: %d, data: %p, size: %d.", (int)eventId, data, (int)len); + return; + } + + switch (eventId) + { + case IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_ENABLED_STATUS: + { + IARM_BUS_NetSrvMgr_Iface_EventInterfaceEnabledStatus_t *e = (IARM_BUS_NetSrvMgr_Iface_EventInterfaceEnabledStatus_t*) data; + NMLOG_INFO ("IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_ENABLED_STATUS :: %s", e->interface); + if (e->status) + ::_instance->ReportInterfaceStateChangedEvent(Exchange::INetworkManager::INTERFACE_ADDED, string(e->interface)); + else + ::_instance->ReportInterfaceStateChangedEvent(Exchange::INetworkManager::INTERFACE_REMOVED, string(e->interface)); + break; + } + case IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_CONNECTION_STATUS: + { + IARM_BUS_NetSrvMgr_Iface_EventInterfaceConnectionStatus_t *e = (IARM_BUS_NetSrvMgr_Iface_EventInterfaceConnectionStatus_t*) data; + NMLOG_INFO ("IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_CONNECTION_STATUS :: %s", e->interface); + if (e->status) + ::_instance->ReportInterfaceStateChangedEvent(Exchange::INetworkManager::INTERFACE_LINK_UP, string(e->interface)); + else + ::_instance->ReportInterfaceStateChangedEvent(Exchange::INetworkManager::INTERFACE_LINK_DOWN, string(e->interface)); + break; + } + case IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_IPADDRESS: + { + IARM_BUS_NetSrvMgr_Iface_EventInterfaceIPAddress_t *e = (IARM_BUS_NetSrvMgr_Iface_EventInterfaceIPAddress_t*) data; + NMLOG_INFO ("IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_IPADDRESS :: %s -- %s", e->interface, e->ip_address); + + ::_instance->ReportIPAddressChangedEvent(string(e->interface), e->acquired, e->is_ipv6, string(e->ip_address)); + break; + } + case IARM_BUS_NETWORK_MANAGER_EVENT_DEFAULT_INTERFACE: + { + IARM_BUS_NetSrvMgr_Iface_EventDefaultInterface_t *e = (IARM_BUS_NetSrvMgr_Iface_EventDefaultInterface_t*) data; + NMLOG_INFO ("IARM_BUS_NETWORK_MANAGER_EVENT_DEFAULT_INTERFACE %s :: %s..", e->oldInterface, e->newInterface); + + ::_instance->ReportActiveInterfaceChangedEvent(e->oldInterface, e->newInterface); + break; + } + case IARM_BUS_WIFI_MGR_EVENT_onAvailableSSIDs: + { + IARM_BUS_WiFiSrvMgr_EventData_t *e = (IARM_BUS_WiFiSrvMgr_EventData_t*) data; + NMLOG_INFO ("IARM_BUS_WIFI_MGR_EVENT_onAvailableSSIDs"); + std::string serialized(e->data.wifiSSIDList.ssid_list); + JsonObject eventDocument; + WPEC::OptionalType error; + if (!WPEJ::IElement::FromString(serialized, eventDocument, error)) { + NMLOG_ERROR("Failed to parse JSON document containing SSIDs. Due to: %s", WPEJ::ErrorDisplayMessage(error).c_str()); + break; + } + if ((!eventDocument.HasLabel("getAvailableSSIDs")) || (eventDocument["getAvailableSSIDs"].Content() != WPEJ::Variant::type::ARRAY)) { + NMLOG_ERROR("JSON document does not have key 'getAvailableSSIDs' as array"); + break; + } + + JsonArray ssids = eventDocument["getAvailableSSIDs"].Array(); + string json; + ssids.ToString(json); + + ::_instance->ReportAvailableSSIDsEvent(json); + } + case IARM_BUS_WIFI_MGR_EVENT_onWIFIStateChanged: + { + IARM_BUS_WiFiSrvMgr_EventData_t* e = (IARM_BUS_WiFiSrvMgr_EventData_t *) data; + Exchange::INetworkManager::WiFiState state = Exchange::INetworkManager::WIFI_STATE_DISCONNECTED; + NMLOG_INFO("Event IARM_BUS_WIFI_MGR_EVENT_onWIFIStateChanged received; state=%d", e->data.wifiStateChange.state); + + state = to_wifi_state(e->data.wifiStateChange.state); + if(e->data.wifiStateChange.state == WIFI_CONNECTED) + ::_instance->wifiSignalStrengthMonitor.startWifiSignalStrengthMonitor(DEFAULT_WIFI_SIGNAL_TEST_INTERVAL_SEC); + ::_instance->ReportWiFiStateChangedEvent(state); + break; + } + default: + { + NMLOG_INFO("Event %d received; Unhandled", eventId); + break; + } + } + } + else + NMLOG_WARNING("WARNING - cannot handle IARM events without a Network plugin instance!"); + } + + void NetworkManagerImplementation::platform_init() + { + LOG_ENTRY_FUNCTION(); + char c; + + ::_instance = this; + + IARM_Result_t res = IARM_Bus_Init("netsrvmgr-thunder"); + NMLOG_INFO("IARM_Bus_Init: %d", res); + if (res == IARM_RESULT_SUCCESS || res == IARM_RESULT_INVALID_STATE /* already inited or connected */) { + res = IARM_Bus_Connect(); + NMLOG_INFO("IARM_Bus_Connect: %d", res); + } else { + NMLOG_ERROR("IARM_Bus_Init failure: %d", res); + } + + + IARM_Result_t retVal = IARM_RESULT_SUCCESS; + + uint32_t retry = 0; + do{ + retVal = IARM_Bus_Call_with_IPCTimeout(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_isAvailable, (void *)&c, sizeof(c), (1000*10)); + if(retVal != IARM_RESULT_SUCCESS){ + NMLOG_INFO("NetSrvMgr is not available. Failed to activate Network Plugin, retry = %d", retry); + usleep(500*1000); + retry++; + } + }while((retVal != IARM_RESULT_SUCCESS) && (retry < 50)); + + if(retVal != IARM_RESULT_SUCCESS) + { + string msg = "NetSrvMgr is not available"; + NMLOG_INFO("NETWORK_NOT_READY: The NetSrvMgr Component is not available.Retrying in separate thread ::%s::", msg.c_str()); + } + else { + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_ENABLED_STATUS, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_CONNECTION_STATUS, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_IPADDRESS, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETWORK_MANAGER_EVENT_DEFAULT_INTERFACE, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETWORK_MANAGER_EVENT_INTERNET_CONNECTION_CHANGED, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_EVENT_onWIFIStateChanged, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_EVENT_onError, NetworkManagerInternalEventHandler); + IARM_Bus_RegisterEventHandler(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_EVENT_onAvailableSSIDs, NetworkManagerInternalEventHandler); + } + } + + uint32_t NetworkManagerImplementation::GetAvailableInterfaces (Exchange::INetworkManager::IInterfaceDetailsIterator*& interfacesItr/* @out */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_BUS_NetSrvMgr_InterfaceList_t list; + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getInterfaceList, (void*)&list, sizeof(list))) + { + std::vector interfaceList; + for (int i = 0; i < list.size; i++) + { + NMLOG_INFO ("Interface Name = %s", list.interfaces[i].name); + string interfaceName(list.interfaces[i].name); + if (("eth0" == interfaceName) || ("wlan0" == interfaceName)) + { + InterfaceDetails tmp; + /* Update the interface as per RDK NetSrvMgr */ + if ("eth0" == interfaceName) + tmp.m_type = string("ETHERNET"); + else if ("wlan0" == interfaceName) + tmp.m_type = string("WIFI"); + + tmp.m_name = interfaceName; + tmp.m_mac = string(list.interfaces[i].mac); + tmp.m_isEnabled = ((list.interfaces[i].flags & IFF_UP) != 0); + tmp.m_isConnected = ((list.interfaces[i].flags & IFF_RUNNING) != 0); + interfaceList.push_back(tmp); + } + } + using Implementation = RPC::IteratorType; + interfacesItr = Core::Service::Create(interfaceList); + + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("Call to %s for %s failed", IARM_BUS_NM_SRV_MGR_NAME, __FUNCTION__); + } + + return rc; + } + + /* @brief Get the active Interface used for external world communication */ + uint32_t NetworkManagerImplementation::GetPrimaryInterface (string& interface /* @out */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_BUS_NetSrvMgr_DefaultRoute_t defaultRoute = {0}; + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getDefaultInterface, (void*)&defaultRoute, sizeof(defaultRoute))) + { + NMLOG_INFO ("Call to %s for %s returned interface = %s, gateway = %s", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getDefaultInterface, defaultRoute.interface, defaultRoute.gateway); + interface = m_defaultInterface = defaultRoute.interface; + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("Call to %s for %s failed", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getDefaultInterface); + } + return rc; + } + + /* @brief Set the active Interface used for external world communication */ + uint32_t NetworkManagerImplementation::SetPrimaryInterface (const string& interface/* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_BUS_NetSrvMgr_Iface_EventData_t iarmData = { 0 }; + iarmData.persist = true; + + /* Netsrvmgr returns eth0 & wlan0 as primary interface but when we want to set., we must set ETHERNET or WIFI*/ + //TODO: Fix netsrvmgr to accept eth0 & wlan0 + if ("wlan0" == interface) + strncpy(iarmData.setInterface, "WIFI", INTERFACE_SIZE); + else if ("eth0" == interface) + strncpy(iarmData.setInterface, "ETHERNET", INTERFACE_SIZE); + else + { + rc = Core::ERROR_BAD_REQUEST; + return rc; + } + + if (IARM_RESULT_SUCCESS == IARM_Bus_Call (IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setDefaultInterface, (void *)&iarmData, sizeof(iarmData))) + { + NMLOG_INFO ("Call to %s for %s success", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setDefaultInterface); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("Call to %s for %s failed", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setDefaultInterface); + } + return rc; + } + + uint32_t NetworkManagerImplementation::EnableInterface (const string& interface/* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_BUS_NetSrvMgr_Iface_EventData_t iarmData = { 0 }; + + /* Netsrvmgr returns eth0 & wlan0 as primary interface but when we want to set., we must set ETHERNET or WIFI*/ + //TODO: Fix netsrvmgr to accept eth0 & wlan0 + if ("wlan0" == interface) + strncpy(iarmData.setInterface, "WIFI", INTERFACE_SIZE); + else if ("eth0" == interface) + strncpy(iarmData.setInterface, "ETHERNET", INTERFACE_SIZE); + else + { + rc = Core::ERROR_BAD_REQUEST; + return rc; + } + + iarmData.isInterfaceEnabled = true; + iarmData.persist = true; + if (IARM_RESULT_SUCCESS == IARM_Bus_Call (IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setInterfaceEnabled, (void *)&iarmData, sizeof(iarmData))) + { + NMLOG_INFO ("Call to %s for %s success", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setInterfaceEnabled); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("Call to %s for %s failed", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setInterfaceEnabled); + } + return rc; + } + + uint32_t NetworkManagerImplementation::DisableInterface (const string& interface/* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_BUS_NetSrvMgr_Iface_EventData_t iarmData = { 0 }; + + /* Netsrvmgr returns eth0 & wlan0 as primary interface but when we want to set., we must set ETHERNET or WIFI*/ + //TODO: Fix netsrvmgr to accept eth0 & wlan0 + if ("wlan0" == interface) + strncpy(iarmData.setInterface, "WIFI", INTERFACE_SIZE); + else if ("eth0" == interface) + strncpy(iarmData.setInterface, "ETHERNET", INTERFACE_SIZE); + else + { + rc = Core::ERROR_BAD_REQUEST; + return rc; + } + + iarmData.isInterfaceEnabled = false; + iarmData.persist = true; + if (IARM_RESULT_SUCCESS == IARM_Bus_Call (IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setInterfaceEnabled, (void *)&iarmData, sizeof(iarmData))) + { + NMLOG_INFO ("Call to %s for %s success", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setInterfaceEnabled); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("Call to %s for %s failed", IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setInterfaceEnabled); + } + return rc; + } + + /* @brief Get IP Address Of the Interface */ + uint32_t NetworkManagerImplementation::GetIPSettings(const string& interface /* @in */, const string& ipversion /* @in */, IPAddressInfo& result /* @out */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_BUS_NetSrvMgr_Iface_Settings_t iarmData = { 0 }; + /* Netsrvmgr returns eth0 & wlan0 as primary interface but when we want to set., we must set ETHERNET or WIFI*/ + //TODO: Fix netsrvmgr to accept eth0 & wlan0 + if ("wlan0" == interface) + strncpy(iarmData.interface, "WIFI", INTERFACE_SIZE); + else if ("eth0" == interface) + strncpy(iarmData.interface, "ETHERNET", INTERFACE_SIZE); + + strncpy(iarmData.ipversion, ipversion.c_str(), 16); + iarmData.isSupported = true; + NMLOG_INFO("NetworkManagerImplementation::GetIPSettings - Before Calling IARM"); + if (IARM_RESULT_SUCCESS == IARM_Bus_Call (IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_getIPSettings, (void *)&iarmData, sizeof(iarmData))) + { + NMLOG_INFO("NetworkManagerImplementation::GetIPSettings - IARM Success.. Filling the data"); + result.m_ipAddrType = string(iarmData.ipversion); + result.m_autoConfig = iarmData.autoconfig; + result.m_dhcpServer = string(iarmData.dhcpserver,MAX_IP_ADDRESS_LEN - 1); + result.m_v6LinkLocal = ""; + result.m_ipAddress = string(iarmData.ipaddress,MAX_IP_ADDRESS_LEN - 1); + result.m_prefix = 0; + result.m_gateway = string(iarmData.gateway,MAX_IP_ADDRESS_LEN - 1); + result.m_primaryDns = string(iarmData.primarydns,MAX_IP_ADDRESS_LEN - 1); + result.m_secondaryDns = string(iarmData.secondarydns,MAX_IP_ADDRESS_LEN - 1); + NMLOG_INFO("NetworkManagerImplementation::GetIPSettings - IARM Success.. Filled the data"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR("NetworkManagerImplementation::GetIPSettings - Calling IARM Failed"); + } + + return rc; + } + +#define CIDR_NETMASK_IP_LEN 32 +const string CIDR_PREFIXES[CIDR_NETMASK_IP_LEN] = { + "128.0.0.0", + "192.0.0.0", + "224.0.0.0", + "240.0.0.0", + "248.0.0.0", + "252.0.0.0", + "254.0.0.0", + "255.0.0.0", + "255.128.0.0", + "255.192.0.0", + "255.224.0.0", + "255.240.0.0", + "255.248.0.0", + "255.252.0.0", + "255.254.0.0", + "255.255.0.0", + "255.255.128.0", + "255.255.192.0", + "255.255.224.0", + "255.255.240.0", + "255.255.248.0", + "255.255.252.0", + "255.255.254.0", + "255.255.255.0", + "255.255.255.128", + "255.255.255.192", + "255.255.255.224", + "255.255.255.240", + "255.255.255.248", + "255.255.255.252", + "255.255.255.254", + "255.255.255.255", + }; + + /* @brief Set IP Address Of the Interface */ + uint32_t NetworkManagerImplementation::SetIPSettings(const string& interface /* @in */, const string &ipversion /* @in */, const IPAddressInfo& address /* @in */) + { + uint32_t rc = Core::ERROR_NONE; + if (0 == strcasecmp("ipv4", ipversion.c_str())) + { + IARM_BUS_NetSrvMgr_Iface_Settings_t iarmData = {0}; + /* Netsrvmgr returns eth0 & wlan0 as primary interface but when we want to set., we must set ETHERNET or WIFI*/ + //TODO: Fix netsrvmgr to accept eth0 & wlan0 + if ("wlan0" == interface) + strncpy(iarmData.interface, "WIFI", INTERFACE_SIZE); + else if ("eth0" == interface) + strncpy(iarmData.interface, "ETHERNET", INTERFACE_SIZE); + else + { + rc = Core::ERROR_BAD_REQUEST; + return rc; + } + /* IP version */ + strncpy(iarmData.ipversion, ipversion.c_str(), 16); + + if (!address.m_autoConfig) + { + //Lets validate the prefix Address + if (address.m_prefix >= 32) + { + rc = Core::ERROR_BAD_REQUEST; + } + else + { + string netmask = CIDR_PREFIXES[address.m_prefix]; + + //Lets validate the IP Address + struct in_addr tmpIPAddress, tmpGWAddress, tmpNetmask; + struct in_addr bcastAddr1, bcastAddr2; + + if (inet_pton(AF_INET, address.m_ipAddress.c_str(), &tmpIPAddress) == 1 && + inet_pton(AF_INET, netmask.c_str(), &tmpNetmask) == 1 && + inet_pton(AF_INET, address.m_gateway.c_str(), &tmpGWAddress) == 1) + { + bcastAddr1.s_addr = tmpIPAddress.s_addr | ~tmpNetmask.s_addr; + bcastAddr2.s_addr = tmpGWAddress.s_addr | ~tmpNetmask.s_addr; + + if (tmpIPAddress.s_addr == tmpGWAddress.s_addr) + { + NMLOG_INFO("Interface and Gateway IP are same , return false"); + rc = Core::ERROR_BAD_REQUEST; + } + if (bcastAddr1.s_addr != bcastAddr2.s_addr) + { + NMLOG_INFO("Interface and Gateway IP is not in same broadcast domain, return false"); + rc = Core::ERROR_BAD_REQUEST; + } + if (tmpIPAddress.s_addr == bcastAddr1.s_addr) + { + NMLOG_INFO("Interface and Broadcast IP is same, return false"); + rc = Core::ERROR_BAD_REQUEST; + } + if (tmpGWAddress.s_addr == bcastAddr2.s_addr) + { + NMLOG_INFO("Gateway and Broadcast IP is same, return false"); + rc = Core::ERROR_BAD_REQUEST; + } + } + else + { + rc = Core::ERROR_BAD_REQUEST; + NMLOG_INFO ("Given Input Address are not appropriate"); + } + + if (Core::ERROR_NONE == rc) + { + strncpy(iarmData.ipaddress, address.m_ipAddress.c_str(), 16); + strncpy(iarmData.netmask, netmask.c_str(), 16); + strncpy(iarmData.gateway, address.m_gateway.c_str(), 16); + strncpy(iarmData.primarydns, address.m_primaryDns.c_str(), 16); + strncpy(iarmData.secondarydns, address.m_secondaryDns.c_str(), 16); + } + } + } + else + { + iarmData.autoconfig = address.m_autoConfig; + } + if (Core::ERROR_NONE == rc) + { + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_NETSRVMGR_API_setIPSettings, (void *) &iarmData, sizeof(iarmData))) + { + NMLOG_INFO("Set IP Successfully"); + } + else + { + NMLOG_ERROR("Setting IP Failed"); + rc = Core::ERROR_RPC_CALL_FAILED; + } + } + } + else + { + //FIXME : Add IPv6 support here + NMLOG_WARNING ("Setting IPv6 is not supported at this point in time. This is just a place holder"); + rc = Core::ERROR_NOT_SUPPORTED; + } + + return rc; + } + + uint32_t NetworkManagerImplementation::StartWiFiScan(const WiFiFrequency frequency /* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_SsidList_Param_t param; + IARM_Result_t retVal = IARM_RESULT_SUCCESS; + + memset(¶m, 0, sizeof(param)); + (void) frequency; + + retVal = IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_getAvailableSSIDsAsync, (void *)¶m, sizeof(IARM_Bus_WiFiSrvMgr_SsidList_Param_t)); + + if(retVal == IARM_RESULT_SUCCESS) { + NMLOG_INFO ("Scan started"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("StartScan failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::StopWiFiScan(void) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_stopProgressiveWifiScanning, (void*) ¶m, sizeof(IARM_Bus_WiFiSrvMgr_Param_t))) + { + NMLOG_INFO ("StopScan Success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("StopScan failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::GetKnownSSIDs(IStringIterator*& ssids /* @out */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Result_t retVal = IARM_RESULT_SUCCESS; + IARM_Bus_WiFiSrvMgr_Param_t param; + + memset(¶m, 0, sizeof(param)); + + /* Must add new method to get all the known SSIDs but for now RDK-NM supports only one active SSID. So we repurpose this method */ + retVal = IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_getConnectedSSID, (void *)¶m, sizeof(param)); + + if(retVal == IARM_RESULT_SUCCESS) + { + auto &connectedSsid = param.data.getConnectedSSID; + std::list ssidList; + ssidList.push_back(string(connectedSsid.ssid)); + NMLOG_INFO ("GetKnownSSIDs Success"); + + ssids = Core::Service::Create(ssidList); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("GetKnownSSIDs failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::AddToKnownSSIDs(const WiFiConnectTo& ssid /* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + strncpy(param.data.connect.ssid, ssid.m_ssid.c_str(), SSID_SIZE - 1); + strncpy(param.data.connect.passphrase, ssid.m_passphrase.c_str(), PASSPHRASE_BUFF - 1); + param.data.connect.security_mode = (SsidSecurity) ssid.m_securityMode; + + IARM_Result_t retVal = IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_saveSSID, (void *)¶m, sizeof(param)); + if(retVal == IARM_RESULT_SUCCESS) + { + NMLOG_INFO ("AddToKnownSSIDs Success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("AddToKnownSSIDs failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::RemoveKnownSSID(const string& ssid /* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + /* Currently RDK-NM supports only one saved SSID. So when you say clear, it jsut clears it. No need to pass input at this point in time. + Will be updated to pass specific ssid when we support more than 1 ssid. + */ + (void)ssid; + + IARM_Result_t retVal = IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_clearSSID, (void *)¶m, sizeof(param)); + if(retVal == IARM_RESULT_SUCCESS) + { + NMLOG_INFO ("RemoveKnownSSID Success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("RemoveKnownSSID failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::WiFiConnect(const WiFiConnectTo& ssid /* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Result_t retVal = IARM_RESULT_SUCCESS; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + if(ssid.m_ssid.length() || ssid.m_passphrase.length()) + { + ssid.m_ssid.copy(param.data.connect.ssid, sizeof(param.data.connect.ssid) - 1); + ssid.m_passphrase.copy(param.data.connect.passphrase, sizeof(param.data.connect.passphrase) - 1); + param.data.connect.security_mode = (SsidSecurity)ssid.m_securityMode; + } + + retVal = IARM_Bus_Call( IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_connect, (void *)¶m, sizeof(param)); + + if(retVal == IARM_RESULT_SUCCESS && param.status) + { + NMLOG_INFO ("WiFiConnect Success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("WiFiConnect failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::WiFiDisconnect(void) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_disconnectSSID, (void *)¶m, sizeof(param))) + { + NMLOG_INFO ("WiFiDisconnect started"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("WiFiDisconnect failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::GetConnectedSSID(WiFiSSIDInfo& ssidInfo /* @out */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Result_t retVal = IARM_RESULT_SUCCESS; + IARM_Bus_WiFiSrvMgr_Param_t param; + + memset(¶m, 0, sizeof(param)); + + /* Must add new method to get all the known SSIDs but for now RDK-NM supports only one active SSID. So we repurpose this method */ + retVal = IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_getConnectedSSID, (void *)¶m, sizeof(param)); + + if(retVal == IARM_RESULT_SUCCESS) + { + auto &connectedSsid = param.data.getConnectedSSID; + + ssidInfo.m_ssid = string(connectedSsid.ssid); + ssidInfo.m_bssid = string(connectedSsid.bssid); + ssidInfo.m_securityMode = (WIFISecurityMode) connectedSsid.securityMode; + ssidInfo.m_signalStrength = to_string(connectedSsid.signalStrength); + ssidInfo.m_frequency = ((((float)connectedSsid.frequency)/1000) < 3.0) ? WIFI_FREQUENCY_2_4_GHZ : WIFI_FREQUENCY_5_GHZ; + ssidInfo.m_rate = to_string(connectedSsid.rate); + ssidInfo.m_noise = to_string(connectedSsid.noise); + + NMLOG_INFO ("GetConnectedSSID Success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("GetConnectedSSID failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::GetWiFiSignalStrength(string& ssid /* @out */, string& signalStrength /* @out */, WiFiSignalQuality& quality /* @out */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + WiFiSSIDInfo ssidInfo{}; + float signalStrengthOut = 0.0f; + + if (Core::ERROR_NONE == GetConnectedSSID(ssidInfo)) + { + ssid = ssidInfo.m_ssid; + signalStrength = ssidInfo.m_signalStrength; + + if (!signalStrength.empty()) + { + signalStrengthOut = std::stof(signalStrength.c_str()); + NMLOG_INFO ("WiFiSignalStrength in dB = %s",signalStrengthOut); + } + + if (signalStrengthOut == 0) + { + quality = WIFI_SIGNAL_DISCONNECTED; + signalStrength = "0"; + } + else if (signalStrengthOut >= signalStrengthThresholdExcellent && signalStrengthOut < 0) + { + quality = WIFI_SIGNAL_EXCELLENT; + signalStrength = "100"; + } + else if (signalStrengthOut >= signalStrengthThresholdGood && signalStrengthOut < signalStrengthThresholdExcellent) + { + quality = WIFI_SIGNAL_GOOD; + signalStrength = "75"; + } + else if (signalStrengthOut >= signalStrengthThresholdFair && signalStrengthOut < signalStrengthThresholdGood) + { + quality = WIFI_SIGNAL_FAIR; + signalStrength = "50"; + } + else + { + quality = WIFI_SIGNAL_WEAK; + signalStrength = "25"; + } + + NMLOG_INFO ("GetWiFiSignalStrength success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("GetWiFiSignalStrength failed"); + } + return rc; + } + + uint32_t NetworkManagerImplementation::StartWPS(const WiFiWPS& method /* @in */, const string& wps_pin /* @in */) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_WPS_Parameters_t wps_parameters; + if (method == WIFI_WPS_PBC) + { + wps_parameters.pbc = true; + } + else if (method == WIFI_WPS_PIN) + { + snprintf(wps_parameters.pin, sizeof(wps_parameters.pin), "%s", wps_pin.c_str()); + wps_parameters.pbc = false; + } + else if (method == WIFI_WPS_SERIALIZED_PIN) + { + snprintf(wps_parameters.pin, sizeof(wps_parameters.pin), "xxxxxxxx"); + wps_parameters.pbc = false; + } + + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_initiateWPSPairing2, (void *)&wps_parameters, sizeof(wps_parameters))) + { + NMLOG_INFO ("StartWPS is success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("StartWPS: Failed"); + } + + return rc; + } + + uint32_t NetworkManagerImplementation::StopWPS(void) + { + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + if (IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_cancelWPSPairing, (void *)¶m, sizeof(param))) + { + NMLOG_INFO ("StopWPS is success"); + rc = Core::ERROR_NONE; + } + else + { + NMLOG_ERROR ("StopWPS: Failed"); + } + + return rc; + } + + uint32_t NetworkManagerImplementation::GetWifiState(WiFiState &state) + { + LOG_ENTRY_FUNCTION(); + uint32_t rc = Core::ERROR_RPC_CALL_FAILED; + IARM_Result_t retVal = IARM_RESULT_SUCCESS; + IARM_Bus_WiFiSrvMgr_Param_t param; + memset(¶m, 0, sizeof(param)); + + if(IARM_RESULT_SUCCESS == IARM_Bus_Call(IARM_BUS_NM_SRV_MGR_NAME, IARM_BUS_WIFI_MGR_API_getCurrentState, (void *)¶m, sizeof(param))) + { + state = to_wifi_state(param.data.wifiStatus); + rc = Core::ERROR_NONE; + } + return rc; + } + } +} diff --git a/NetworkManager/service/StunClient.cpp b/NetworkManager/service/StunClient.cpp new file mode 100644 index 0000000000..7bbf01f98a --- /dev/null +++ b/NetworkManager/service/StunClient.cpp @@ -0,0 +1,792 @@ +#include "StunClient.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STUN_DEFAULT_WAIT_INTERVAL 2000 //miliseconds +#define STUN_DEFAULT_MAX_ATTEMPTS 30 + +//#define _STUN_DEBUG 1 +//#define _STUN_USE_MSGHDR + +namespace stun { +namespace details { + static int constexpr binding_requests_max = 9; + static std::chrono::milliseconds binding_requests_wait_time_max(1600); + + static char const * family_to_string(int family) { + if (family == AF_INET) + return "ipv4"; + if (family == AF_INET6) + return "ipv6"; + return "unknown"; + } + + class file_descriptor { + public: + file_descriptor(int n) : m_fd(n) { } + ~file_descriptor() { + if (m_fd > 0) + close(m_fd); + } + operator int() const { return m_fd; } + private: + int m_fd; + }; + + #ifdef _STUN_DEBUG + void dump_buffer(char const * prefix, buffer const & buff) + { + if (prefix) + printf("%s", prefix); + for (uint8_t b : buff) + printf("0x%02x ", b); + printf("\n"); + return; + } + #endif + + #ifdef _STUN_DEBUG + #define STUN_TRACE(format, ...) printf("STUN:" format __VA_OPT__(,) __VA_ARGS__) + #else + #define STUN_TRACE(format, ...) + #endif + + + void throw_error(char const * format, ...) + { + char buff[256] = {}; + + va_list ap; + va_start(ap, format); + vsnprintf(buff, sizeof(buff) - 1, format, ap); + va_end(ap); + + buff[255] = '\0'; +#ifdef __cpp_exceptions + throw std::runtime_error(buff); +#else + printf("%s", buff); +#endif + return; + } + + template + inline void random_fill(iterator begin, iterator end) { + std::random_device rdev; + std::default_random_engine random_engine(rdev()); + std::uniform_int_distribution uniform_dist(0, std::numeric_limits::max()); + while (begin != end) + *begin++ = uniform_dist(random_engine); + } + + sockaddr_storage get_interface_address(std::string const & iface, int family) + { + bool found_iface_info = false; + sockaddr_storage iface_info = {}; + + struct ifaddrs * address_list = nullptr; + if (getifaddrs(&address_list) == -1) { + details::throw_error("getifaddrs failed. %s", strerror(errno)); + return iface_info; + } + + for (auto * addr = address_list; addr != nullptr; addr = addr->ifa_next) { + if (iface != addr->ifa_name) + continue; + if (family != addr->ifa_addr->sa_family) + continue; + iface_info = * reinterpret_cast(addr->ifa_addr); + iface_info.ss_family = addr->ifa_addr->sa_family; + found_iface_info = true; + break; + } + + if (address_list) + freeifaddrs(address_list); + + if (!found_iface_info) { + details::throw_error("failed to find ip for interface:%s", iface.c_str()); + return iface_info; + } + STUN_TRACE("local_addr:%s\n", sockaddr_to_string(iface_info).c_str()); + + return iface_info; + } + + uint16_t sockaddr_get_port(sockaddr_storage const & addr) + { + uint16_t port = 0; + if (addr.ss_family== AF_INET) { + sockaddr_in const * v4 = reinterpret_cast< sockaddr_in const *>(&addr); + port = htons(v4->sin_port); + } + else if (addr.ss_family == AF_INET6) { + sockaddr_in6 const * v6 = reinterpret_cast< sockaddr_in6 const *>(&addr); + port = htons(v6->sin6_port); + } + else + throw_error("can't convert address with family:%d to a string.", addr.ss_family); + + return port; + } + + std::string sockaddr_to_string2(sockaddr const * addr, int family) + { + char buff[INET6_ADDRSTRLEN] = {}; + + char const * p = nullptr; + + if (family == AF_INET) { + sockaddr_in const * v4 = reinterpret_cast< sockaddr_in const *>(addr); + p = inet_ntop(AF_INET, &v4->sin_addr, buff, INET6_ADDRSTRLEN); + } + else if (family == AF_INET6) { + sockaddr_in6 const * v6 = reinterpret_cast< sockaddr_in6 const *>(addr); + p = inet_ntop(AF_INET6, &v6->sin6_addr, buff, INET6_ADDRSTRLEN); + } + else + throw_error("can't convert address with family:%d to a string.", family); + + if (!p) + throw_error("failed to convert address to string"); + + buff[INET6_ADDRSTRLEN - 1] = '\0'; + return std::string(buff); + } + + std::vector resolve_hostname(std::string const & host, uint16_t port, stun::protocol proto) + { + std::vector addrs; + std::set already_seen; + + struct addrinfo * stun_addrs = nullptr; + int ret = getaddrinfo(host.c_str(), nullptr, nullptr, &stun_addrs); + if (ret != 0) { + std::stringstream error_message; + error_message << "getaddrinfo failed. "; + if (ret == EAI_SYSTEM) + error_message << strerror(errno); + else + error_message << gai_strerror(ret); + throw_error(error_message.str().c_str()); + } + + int protocol_family = AF_INET; + if (proto == stun::protocol::af_inet) + protocol_family = AF_INET; + else if (proto == stun::protocol::af_inet6) + protocol_family = AF_INET6; + else + throw_error("invalid protocol family"); + + for (struct addrinfo * addr = stun_addrs; addr; addr = addr->ai_next) { + if (addr->ai_family != AF_INET && addr->ai_family != AF_INET6) + continue; + if (addr->ai_family != protocol_family) + continue; + + std::string const s = sockaddr_to_string2(addr->ai_addr, addr->ai_family); + + if (already_seen.find(s) == std::end(already_seen)) { + struct sockaddr_storage temp = {}; + memcpy(&temp, addr->ai_addr, addr->ai_addrlen); + + if (addr->ai_family == AF_INET) { + sockaddr_in * v4 = reinterpret_cast< sockaddr_in *>(&temp); + v4->sin_port = ntohs(port); + } + else if (addr->ai_family == AF_INET6) { + sockaddr_in6 * v6 = reinterpret_cast< sockaddr_in6 *>(&temp); + v6->sin6_port = ntohs(port); + } + + addrs.push_back(temp); + already_seen.insert(s); + } + } + + if (stun_addrs) + freeaddrinfo(stun_addrs); + + return addrs; + } + + socklen_t socket_length(sockaddr_storage const & addr) + { + if (addr.ss_family == AF_INET) + return sizeof(sockaddr_in); + if (addr.ss_family == AF_INET6) + return sizeof(sockaddr_in6); + return 0; + } + +} // end namespace details + +attribute const * message::find_attribute(uint16_t attr_type) const +{ + std::vector::const_iterator itr = std::find_if ( + std::begin(m_attrs), std::end(m_attrs), [attr_type](attribute const & attr) { + return attr_type == attr.type; + }); + if (itr == m_attrs.end()) + return nullptr; + attribute const & temp = *itr; + return &temp; +} + + +buffer message::encode() const +{ + buffer bytes; + encoder::encode_u16(bytes, m_header.message_type); + encoder::encode_u16(bytes, m_header.message_length); + for (uint8_t b : m_header.transaction_id) + bytes.push_back(static_cast(b)); + for (attribute const & v : m_attrs) { + encoder::encode_u16(bytes, v.type); + encoder::encode_u16(bytes, v.length); + bytes.insert(std::end(bytes), std::begin(v.value), std::end(v.value)); + } + return bytes; +} + +message * message_factory::create_binding_request() +{ + message * change_request = new message(); + change_request->m_header.message_type = 1; + change_request->m_header.message_length = 8; + details::random_fill(std::begin(change_request->m_header.transaction_id), + std::end(change_request->m_header.transaction_id)); + + // CHANGE-REQUEST + change_request->m_attrs.push_back({3, 4, {0, 0, 0, 0}}); + + return change_request; +} + +client::client() + : m_server("", 0) + , m_protocol(protocol::af_inet) + , m_interface("") + , m_bind_timeout(30) + , m_cache_timeout(30) + , m_last_cache_time() + , m_last_result() + , m_verbose(true) + , m_fd(-1) +{ +} + +client::~client() +{ + if (m_fd != -1) + close(m_fd); +} + +bool client::bind( + std::string const & hostname, + uint16_t port, + std::string const & interface, + protocol proto, + uint16_t bind_timeout, + uint16_t cache_timeout, + bind_result& result) +{ + /*if params change then we force a bind request now instead of using any cached value*/ + bool dirty = false; + bool ret_ok = false; + + if(m_server.hostname != hostname) + { + m_server.hostname = hostname; + dirty = true; + } + + if(m_server.port != port) + { + m_server.port = port; + dirty = true; + } + + if(m_interface != interface) + { + m_interface = interface; + dirty = true; + } + + if(m_protocol != proto) + { + m_protocol = proto; + dirty = true; + } + + if(m_bind_timeout != bind_timeout) + { + m_bind_timeout = bind_timeout; + dirty = true; + } + + if(m_cache_timeout != cache_timeout) + { + m_cache_timeout = cache_timeout; + dirty = true; + } + + verbose("client::bind enter: server=%s port=%u iface=%s ipv6=%u timeout=%u cache_timeout=%u dirty=%u\n", + hostname.c_str(), port, interface.c_str(), proto == stun::protocol::af_inet6, bind_timeout, cache_timeout, dirty); + + if(m_cache_timeout > 0 /*asking if caching is enabled*/ + && !dirty /*if dirty then the caller has changed our settings and wants a new bind no matter what*/ + && m_last_result.is_valid()) /*we actually have a valid cached response*/ + { + auto time_in_cache = std::chrono::duration_cast( + std::chrono::steady_clock::now() - m_last_cache_time); + + verbose("client::bind cache time=%lld\n", time_in_cache.count()); + + if(time_in_cache.count() < m_cache_timeout) + { + result = m_last_result; + + verbose("client::bind returning cached result: %s\n", result.public_ip.c_str()); + return true; + } + else + { + verbose("client::client::bind cached result expired\n"); + } + } + + #ifdef __cpp_exceptions + try + #endif + { + int interval_wait_time = STUN_DEFAULT_WAIT_INTERVAL; + int num_attempts = STUN_DEFAULT_MAX_ATTEMPTS; + int total_time = 0; + int sleep_time = 1; + + std::chrono::milliseconds wait_time(interval_wait_time); + for (int i = 0; i < num_attempts && total_time < m_bind_timeout; ++i) + { + verbose("client::bind sending bind request\n"); + + std::unique_ptr binding_response = send_binding_request(wait_time); + + total_time += interval_wait_time;/*FXIME should do a clock delta and not use wait_time which is the max*/ + /*do a multiple of 2 sleep -- FIXIME should use cond variable so user to cancel this*/ + if (i > 0) + { + if (total_time + sleep_time > m_bind_timeout) + sleep_time = m_bind_timeout - total_time; + if (sleep_time < 0) + break; + sleep(sleep_time); + total_time += sleep_time; + if (sleep_time < 32)/*put some max limit on how long we wait*/ + sleep_time *= 2; + } + if (binding_response) + { + stun::attribute const * mapped_address = binding_response->find_attribute(stun::attribute_type::mapped_address); + if (mapped_address) + { + sockaddr_storage addr = stun::attributes::mapped_address(*mapped_address).addr(); + + result.public_ip = m_last_result.public_ip = stun::sockaddr_to_string(addr); + + m_last_cache_time = std::chrono::steady_clock::now(); + + verbose("client::bind success: public_ip=%s\n", result.public_ip.c_str()); + + ret_ok = true; + } + else + { + verbose("client::bind failed: ip missing from binding response\n"); + } + } + else + { + verbose("client::bind failed: no response received from server\n"); + } + } + } +#ifdef __cpp_exceptions + catch (std::exception const & err) + { + verbose("client::bind failed: %s\n", err.what()); + } +#endif + + if (m_fd != -1) + { + close(m_fd); + m_fd = -1; + } + + if(!ret_ok) + result.invalidate(); + + return ret_ok; +} + +void client::create_udp_socket(int inet_family) +{ + if (inet_family != AF_INET && inet_family != AF_INET6) + details::throw_error("invalid inet family:%d", inet_family); + + verbose("creating udp/%s socket\n", details::family_to_string(inet_family)); + + int soc = socket(inet_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (soc < 0) + details::throw_error("error creating socket. %s", strerror(errno)); + + #ifdef _SUN_USE_MSGHDR + int optval = 1; + setsockopt(soc, IPPROTO_IP, IP_PKTINFO, &optval, sizeof(int)); + #endif + + if (!m_interface.empty()) { + sockaddr_storage local_addr = details::get_interface_address(m_interface, inet_family); + + verbose("binding to local interface %s/%s\n", m_interface.c_str(), + sockaddr_to_string(local_addr).c_str()); + + int ret = ::bind(soc, reinterpret_cast(&local_addr), details::socket_length(local_addr)); + if (ret < 0) { + int err = errno; + close(soc); + details::throw_error("failed to bind socket to local address '%s'. %s", + sockaddr_to_string(local_addr).c_str(), strerror(err)); + } + else { + if (m_verbose) { + sockaddr_storage local_endpoint; + socklen_t socklen = sizeof(sockaddr_storage); + int ret = getsockname(soc, reinterpret_cast(&local_endpoint), &socklen); + if (ret == 0) + verbose("local endpoint %s/%d\n", sockaddr_to_string(local_endpoint).c_str(), + details::sockaddr_get_port(local_endpoint)); + } + } + } + else + verbose("no local interface supplied to bind to\n"); + + if (m_fd != -1) + close(m_fd); + m_fd = soc; + return; +} + +message * client::send_message(sockaddr_storage const & remote_addr, message const & req, + std::chrono::milliseconds wait_time, int * local_iface_index) +{ + if (m_fd < 0) + return nullptr; + + buffer bytes = req.encode(); + + STUN_TRACE("remote_addr:%s\n", sockaddr_to_string(remote_addr).c_str()); + + #ifdef _STUN_DEBUG + details::dump_buffer("STUN >>> ", bytes); + #endif + + verbose("sending messsage\n"); + + ssize_t n = sendto(m_fd, &bytes[0], bytes.size(), 0, (sockaddr *) &remote_addr, details::socket_length(remote_addr)); + if (n < 0) + details::throw_error("failed to send packet. %s", strerror(errno)); + + bytes.resize(0); + bytes.reserve(256); + bytes.resize(256); + + sockaddr_storage from_addr = {}; + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(m_fd, &rfds); + + timeval timeout; + timeout.tv_usec = 1000 * wait_time.count(); + timeout.tv_sec = 0; + + constexpr decltype(timeout.tv_sec) kMicrosecondsPerSecond = 1000000; + if (timeout.tv_usec > kMicrosecondsPerSecond) { + timeout.tv_sec = (timeout.tv_usec / kMicrosecondsPerSecond); + timeout.tv_usec -= (timeout.tv_sec * kMicrosecondsPerSecond); + } + verbose("waiting for response, timeout set to %lus - %luus\n", timeout.tv_sec, timeout.tv_usec); + int ret = select(m_fd + 1, &rfds, nullptr, nullptr, &timeout); + if (ret == 0) { + STUN_TRACE("select timeout out\n"); + return nullptr; + } + + // + // XXX: For discovering the network type, the first test is to run a binding request and + // compare the response to the local address/port combo. I was attempting to find the + // local address/port without an explicit bind() on the local socket fd. You can usethe + // recvmsg() to get the interface index where the UDP packets come in, but you can't get + // the port. For now, in order for the discovery to work, you have to choose a local + // interface name, and call bind() on the addr. + // + // At some point, I'll come back to this and check whether you can find the port without + // an explicit bind, possibly using sendmsg() or another option. + // @see [in this file] client::create_udp_socket(), there's a call to setsockopt() which + // enables the retrieval of the IP_PKTINFO + // + #ifdef _STUN_USE_MSGHDR + do { + //buffer control( CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(struct in_pktinfo)) + + // sizeof(struct cmsghdr) ); + uint8_t control_data[256]; + + struct msghdr msg = {}; + struct iovec iov = {}; + + iov.iov_base = &bytes[0]; + iov.iov_len = bytes.size(); + + msg.msg_flags = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control_data; + msg.msg_controllen = sizeof(control_data); + msg.msg_name = &from_addr; + msg.msg_namelen = sizeof(from_addr); + + n = recvmsg(m_fd, &msg, 0); + if ((n > 0) && local_iface_index) { + for (cmsghdr * cptr = CMSG_FIRSTHDR(&msg); cptr; cptr = CMSG_NXTHDR(&msg, cptr)) { + if (cptr->cmsg_level == IPPROTO_IP) { + if (cptr->cmsg_type == IP_PKTINFO) + *local_iface_index = reinterpret_cast(CMSG_DATA(cptr))->ipi_ifindex; + else if (cptr->cmsg_type == IPV6_PKTINFO) + *local_iface_index = reinterpret_cast(CMSG_DATA(cptr))->ipi6_ifindex; + } + } + } + } while (n < 0 && errno == EINTR); + #else + do { + socklen_t len = sizeof(sockaddr_storage); + n = recvfrom(m_fd, &bytes[0], bytes.size(), MSG_WAITALL, (sockaddr *) &from_addr, &len); + } while (n == -2 && errno == EINTR); + #endif + + if (n < 0) + details::throw_error("error receiving on socket. %s", strerror(errno)); + else + bytes.resize(n); + + #ifdef _STUN_DEBUG + details::dump_buffer("STUN <<< ", bytes); + #endif + + return decoder::decode_message(bytes, nullptr); +} + +void client::verbose(char const * format, ...) +{ + if (!m_verbose) + return; + va_list ap; + va_start(ap, format); + printf("STUN:"); + vprintf(format, ap); + va_end(ap); + return; +} + +network_access_type client::discover_network_access_type(server const & srv) +{ + std::chrono::milliseconds wait_time(250); + std::vector addrs = details::resolve_hostname(srv.hostname, srv.port, m_protocol); + + sockaddr_storage server_addr = {}; + + std::unique_ptr binding_response; + for (sockaddr_storage const & addr : addrs) { + binding_response = this->send_binding_request(addr, wait_time); + if (binding_response) { + server_addr = addr; + break; + } + else + wait_time = std::min(wait_time * 2, details::binding_requests_wait_time_max); + } + + if (!binding_response) + return network_access_type::udp_blocked; + + // get endpoint binding_request was sent from and compare to the binding_response + // if they're the same, run "test II". + sockaddr_storage local_endpoint; + socklen_t socklen = sizeof(sockaddr_storage); + int ret = getsockname(m_fd, reinterpret_cast(&local_endpoint), &socklen); + if (ret == -1) + details::throw_error("failed to get local socket name:%s", strerror(errno)); + + local_endpoint.ss_family = AF_INET; + std::string s = sockaddr_to_string(local_endpoint); + + return network_access_type::unknown; +} + +std::unique_ptr client::send_binding_request(std::chrono::milliseconds wait_time) +{ + std::unique_ptr binding_response; + std::vector addrs = details::resolve_hostname(m_server.hostname, m_server.port, m_protocol); + for (sockaddr_storage const & addr : addrs) { + binding_response = this->send_binding_request(addr, wait_time); + if (binding_response) + break; + else + wait_time = std::min(wait_time * 2, details::binding_requests_wait_time_max); + } + return binding_response; +} + +std::unique_ptr client::send_binding_request(sockaddr_storage const & addr, + std::chrono::milliseconds wait_time) +{ + this->verbose("sending binding request with wait time:%lld ms\n", wait_time.count()); + this->create_udp_socket(addr.ss_family); + std::unique_ptr binding_request(message_factory::create_binding_request()); + std::unique_ptr binding_response(this->send_message(addr, *binding_request, wait_time)); + return binding_response; +} + +attributes::address::address(attribute const & attr) +{ + size_t offset = 0; + + // the family is actually 8-bits, but the pkt has a 1 byte padding + // for alignment + uint16_t family = decoder::decode_u16(attr.value, &offset); + if (family == 1) { + sockaddr_in * v4 = reinterpret_cast(&m_addr); + v4->sin_port = decoder::decode_u16(attr.value, &offset); + v4->sin_addr.s_addr = htonl(decoder::decode_u32(attr.value, &offset)); + m_addr = * reinterpret_cast(v4); + m_addr.ss_family = AF_INET; + } + else if (family == 2) { + sockaddr_in6 * v6 = reinterpret_cast(&m_addr); + v6->sin6_port = decoder::decode_u16(attr.value, &offset); + for (int i = 0; i < 16; ++i) + v6->sin6_addr.s6_addr[i] = attr.value[offset + i]; + m_addr = * reinterpret_cast(v6); + m_addr.ss_family = AF_INET6; + } + else + details::throw_error("invalid mapped address family:%d", family); +} + +uint32_t decoder::decode_u32(buffer const & buff, size_t * offset) +{ + uint32_t const * p = reinterpret_cast(&buff[*offset]); + uint32_t value = ntohl(*p); + *offset += 4; + return value; +} + +uint16_t decoder::decode_u16(buffer const & buff, size_t * offset) +{ + uint16_t const * p = reinterpret_cast(&buff[*offset]); + uint16_t value = ntohs(*p); + *offset += 2; + return value; +} + +message * decoder::decode_message(buffer const & buff, size_t * offset) +{ + size_t temp_offset = 0; + if (offset) + temp_offset = *offset; + + // TODO: use a factory + // create a map[ message_type ] = message_factory_method + + message * new_message = nullptr; + message_header header; + header.message_type = decoder::decode_u16(buff, &temp_offset); + header.message_length = decoder::decode_u16(buff, &temp_offset); + if (header.message_type == message_type::binding_response) { + for (size_t i = 0, n = header.transaction_id.size(); i < n; ++i) + header.transaction_id[i] = buff[temp_offset++ + i]; + new_message = new message(); + new_message->m_header = header; + while (temp_offset < buff.size()) + new_message->m_attrs.push_back(decoder::decode_attr(buff, &temp_offset)); + } + else { + // TODO: unsupported message type + } + + if (offset) + *offset = temp_offset; + + return new_message; +} + +attribute decoder::decode_attr(buffer const & buff, size_t * offset) +{ + attribute t = {}; + t.type = decoder::decode_u16(buff, offset); + t.length = decoder::decode_u16(buff, offset); + t.value.insert(std::end(t.value), std::begin(buff) + *offset, + std::begin(buff) + *offset + t.length); + *offset += t.value.size(); + return t; +} + +void encoder::encode_u16(buffer & buff, uint16_t n) +{ + uint16_t temp = htons(n); + uint8_t * p = reinterpret_cast< uint8_t * >(&temp); + buff.push_back(p[0]); + buff.push_back(p[1]); + return; +} + +void encoder::encode_u32(buffer & buff, uint32_t n) +{ + uint32_t temp = htons(n); + uint8_t * p = reinterpret_cast(&temp); + buff.push_back(p[0]); + buff.push_back(p[1]); + buff.push_back(p[2]); + buff.push_back(p[3]); + return; +} + +std::string sockaddr_to_string(sockaddr_storage const & addr) +{ + sockaddr const * temp = reinterpret_cast(&addr); + return details::sockaddr_to_string2(temp, addr.ss_family); +} + +} // end namespace stun diff --git a/NetworkManager/service/StunClient.h b/NetworkManager/service/StunClient.h new file mode 100644 index 0000000000..c2f69297ab --- /dev/null +++ b/NetworkManager/service/StunClient.h @@ -0,0 +1,191 @@ +#ifndef STUN_CLIENT_H +#define STUN_CLIENT_H + +#include +#include +#include +#include +#include +#include +#include + +namespace stun +{ + +class encoder; +class decoder; +class message; +class message_factory; + +using buffer = std::vector; + +enum class network_access_type { + udp_blocked, + open_internet, + symmetric_firewall, + full_cone, + symmetric_nat, + restricted, + port_resricted, + unknown +}; + +namespace message_type { + static uint16_t constexpr binding_request = 0x001; + static uint16_t constexpr binding_response = 0x0101; + static uint16_t constexpr binding_error_response = 0x0111; + static uint16_t constexpr shared_secret_request = 0x0002; + static uint16_t constexpr shared_secret_response = 0x0102; + static uint16_t constexpr shared_secret_error_response = 0x0112; +} + +namespace attribute_type { + static uint16_t constexpr mapped_address = 0x001; + static uint16_t constexpr response_address = 0x0002; + static uint16_t constexpr change_request = 0x0003; + static uint16_t constexpr source_address = 0x004; + static uint16_t constexpr changed_address = 0x005; + static uint16_t constexpr username = 0x0006; + static uint16_t constexpr password = 0x0007; + static uint16_t constexpr message_integrity = 0x0008; + static uint16_t constexpr error_code = 0x0009; + static uint16_t constexpr unknown_attributes = 0x000a; + static uint16_t constexpr reflected_from = 0x000b; +} + +struct attribute { + uint16_t type; + uint16_t length; + std::vector value; +}; + +namespace attributes { + class address { + public: + address(attribute const & attr); + inline sockaddr_storage addr() const { + return m_addr; + } + private: + sockaddr_storage m_addr; + }; + struct mapped_address : public address { + mapped_address(attribute const & attr) : address(attr) { } + }; + struct source_address : public address { + source_address(attribute const & attr) : address(attr) { } + }; + struct changed_address : public address { + changed_address(attribute const & attr) : address(attr) { } + }; +} + +struct message_header { + uint16_t message_type; + uint16_t message_length; + std::array transaction_id; +}; + +class message { + friend class encoder; + friend class decoder; + friend class message_factory; +public: + buffer encode() const; + inline std::vector const & attributes() const { + return m_attrs; + } + + attribute const * find_attribute(uint16_t attr_type) const; + +private: + message_header m_header; + std::vector m_attrs; +}; + +class message_factory final { +public: + static message * create_binding_request(); +}; + +class decoder final { +public: + static uint16_t decode_u16(buffer const & buff, size_t * offset); + static uint32_t decode_u32(buffer const & buff, size_t * offset); + static attribute decode_attr(buffer const & buff, size_t * offset); + static message * decode_message(buffer const & buff, size_t * offset); +}; + +class encoder final { +public: + static void encode_u16(buffer & buff, uint16_t n); + static void encode_u32(buffer & buff, uint32_t n); +}; + +struct server { + server(std::string const& h, uint16_t p) + : hostname(h), port(p) + {} + std::string hostname; + uint16_t port; +}; + +enum class protocol { + af_inet, + af_inet6 +}; + +struct bind_result { + bind_result() : public_ip() {} + bool is_valid() { return !public_ip.empty(); } + void invalidate() { public_ip.clear(); } + std::string public_ip; +}; + +class client { +public: + client(); + ~client(); + + bool bind(std::string const & hostname, + uint16_t port, + std::string const & interface, + protocol proto, + uint16_t bind_timeout, + uint16_t cache_timeout, + bind_result& result); + + network_access_type discover_network_access_type(server const & srv); + + inline void set_verbose(bool b) { + m_verbose = b; + } +private: + void verbose(char const * format, ...) __attribute__((format(printf, 2, 3))); + void create_udp_socket(int inet_family); + + std::unique_ptr send_binding_request(std::chrono::milliseconds wait_time); + + std::unique_ptr send_binding_request(sockaddr_storage const & addr, + std::chrono::milliseconds wait_time); + + message * send_message(sockaddr_storage const & remote_adr, message const & req, + std::chrono::milliseconds wait_time, int * local_iface_index = nullptr); + +private: + server m_server; + protocol m_protocol; + std::string m_interface; + uint16_t m_bind_timeout; + uint16_t m_cache_timeout; + std::chrono::time_point m_last_cache_time; + bind_result m_last_result; + bool m_verbose; + int m_fd; +}; + +std::string sockaddr_to_string(sockaddr_storage const & addr); + +} + +#endif diff --git a/NetworkManager/service/WiFiManager.conf.in b/NetworkManager/service/WiFiManager.conf.in new file mode 100644 index 0000000000..04af7b23b3 --- /dev/null +++ b/NetworkManager/service/WiFiManager.conf.in @@ -0,0 +1,25 @@ +autostart = "true" +callsign= "org.rdk.Wifi" + +test = JSON() +test.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") +test.add("outofprocess", "true") + +connectivity = JSON() +connectivity.add("endpoint_1", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_1@") +connectivity.add("endpoint_2", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_2@") +connectivity.add("endpoint_3", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_3@") +connectivity.add("endpoint_4", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_4@") +connectivity.add("endpoint_5", "@PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_5@") +connectivity.add("interval", "@PLUGIN_NETWORKMANAGER_CONN_MONITOR_INTERVAL@") + +stun = JSON() +stun.add("endpoint", "@PLUGIN_NETWORKMANAGER_STUN_ENDPOINT@") +stun.add("port", "@PLUGIN_NETWORKMANAGER_STUN_PORT@") +stun.add("interval", "30") + +configuration = JSON() +configuration.add("root", test) +configuration.add("connectivity", connectivity) +configuration.add("stun", stun) +configuration.add("loglevel", "@PLUGIN_NETWORKMANAGER_LOGLEVEL@") diff --git a/NetworkManager/service/WiFiManager.config b/NetworkManager/service/WiFiManager.config new file mode 100644 index 0000000000..25211f2092 --- /dev/null +++ b/NetworkManager/service/WiFiManager.config @@ -0,0 +1,28 @@ +set(autostart true) +set(callsign "org.rdk.Wifi") + +map() + key(root) + map() + kv(outofprocess true) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() + key(connectivity) + map() + kv(endpoint_1 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_1}) + kv(endpoint_2 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_2}) + kv(endpoint_3 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_3}) + kv(endpoint_4 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_4}) + kv(endpoint_5 ${PLUGIN_NETWORKMANAGER_CONN_ENDPOINT_5}) + kv(interval, @PLUGIN_NETWORKMANAGER_CONN_MONITOR_INTERVAL@) + end() + key(stun) + map() + kv(endpoint, ${PLUGIN_NETWORKMANAGER_STUN_ENDPOINT}) + kv(port, PLUGIN_NETWORKMANAGER_STUN_PORT) + kv(interval, 30) + end() + kv(loglevel, 3) +end() +ans(configuration) + diff --git a/NetworkManager/service/WifiSignalStrengthMonitor.cpp b/NetworkManager/service/WifiSignalStrengthMonitor.cpp new file mode 100644 index 0000000000..f448e00e71 --- /dev/null +++ b/NetworkManager/service/WifiSignalStrengthMonitor.cpp @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include "NetworkManagerLogger.h" +#include "NetworkManagerImplementation.h" +#include "WifiSignalStrengthMonitor.h" + +#define BUFFER_SIZE 512 +#define rssid_command "wpa_cli signal_poll" +#define ssid_command "wpa_cli status" + +namespace WPEFramework +{ + namespace Plugin + { + static const float signalStrengthThresholdExcellent = -50.0f; + static const float signalStrengthThresholdGood = -60.0f; + static const float signalStrengthThresholdFair = -67.0f; + extern NetworkManagerImplementation* _instance; + + std::string WifiSignalStrengthMonitor::retrieveValues(const char *command, const char* keyword, char *output_buffer, size_t output_buffer_size) + { + std::string key, value; + std::string keystr = ""; + + FILE *fp = popen(command, "r"); + if (!fp) + { + NMLOG_ERROR("Failed in getting output from command %s \n",command); + return keystr; + } + + while ((!feof(fp)) && (fgets(output_buffer, output_buffer_size, fp) != NULL)) + { + std::istringstream mystream(output_buffer); + if(std::getline(std::getline(mystream, key, '=') >> std::ws, value)) + if (key == keyword) { + keystr = value; + break; + } + } + pclose(fp); + + return keystr; + } + + void WifiSignalStrengthMonitor::getSignalData(std::string &ssid, Exchange::INetworkManager::WiFiSignalQuality &quality, std::string &strengthOut) + { + float signalStrengthOut = 0.0f; + char buff[BUFFER_SIZE] = {'\0'}; + + ssid = retrieveValues(ssid_command, "ssid", buff, sizeof (buff)); + if (ssid.empty()) + { + NMLOG_ERROR("ssid is empty"); + quality = Exchange::INetworkManager::WIFI_SIGNAL_DISCONNECTED; + return; + } + + string signalStrength = retrieveValues(rssid_command, "RSSI", buff, sizeof (buff)); + if (!signalStrength.empty()) + signalStrengthOut = std::stof(signalStrength.c_str()); + else + NMLOG_ERROR("signalStrength is empty"); + + NMLOG_TRACE("SSID = %s Signal Strength %f db", ssid.c_str(), signalStrengthOut); + if (signalStrengthOut == 0.0f) + { + strengthOut = "Disconnected"; + quality = Exchange::INetworkManager::WIFI_SIGNAL_DISCONNECTED; + } + else if (signalStrengthOut >= signalStrengthThresholdExcellent && signalStrengthOut < 0) + { + strengthOut = "Excellent"; + quality = Exchange::INetworkManager::WIFI_SIGNAL_EXCELLENT; + } + else if (signalStrengthOut >= signalStrengthThresholdGood && signalStrengthOut < signalStrengthThresholdExcellent) + { + strengthOut = "Good"; + quality = Exchange::INetworkManager::WIFI_SIGNAL_GOOD; + } + else if (signalStrengthOut >= signalStrengthThresholdFair && signalStrengthOut < signalStrengthThresholdGood) + { + strengthOut = "Fair"; + quality = Exchange::INetworkManager::WIFI_SIGNAL_FAIR; + } + else + { + strengthOut = "Weak"; + quality = Exchange::INetworkManager::WIFI_SIGNAL_WEAK; + }; + } + + void WifiSignalStrengthMonitor::startWifiSignalStrengthMonitor(int interval) + { + stopThread = false; + if (isRunning) { + NMLOG_INFO("WifiSignalStrengthMonitor Thread is already running."); + return; + } + isRunning = true; + monitorThread = std::thread(&WifiSignalStrengthMonitor::monitorThreadFunction, this, interval); + monitorThread.detach(); + std::thread::id threadId = monitorThread.get_id(); + NMLOG_INFO("Thread started with interval: %d seconds. Thread ID: %lu", interval); + } + + void WifiSignalStrengthMonitor::monitorThreadFunction(int interval) + { + static Exchange::INetworkManager::WiFiSignalQuality oldSignalQuality = Exchange::INetworkManager::WIFI_SIGNAL_DISCONNECTED; + NMLOG_INFO("WifiSignalStrengthMonitor thread started !"); + while (!stopThread) + { + string ssid = ""; + string signalStrength; + Exchange::INetworkManager::WiFiSignalQuality newSignalQuality; + if (_instance != nullptr) + { + NMLOG_TRACE("checking WiFi signal strength"); + getSignalData(ssid, newSignalQuality, signalStrength); + if(oldSignalQuality != newSignalQuality) + { + NMLOG_INFO("Notifying WiFiSignalStrengthChangedEvent ...%s", signalStrength.c_str()); + oldSignalQuality = newSignalQuality; + _instance->ReportWiFiSignalStrengthChangedEvent(ssid, signalStrength, newSignalQuality); + } + + if(newSignalQuality == Exchange::INetworkManager::WIFI_SIGNAL_DISCONNECTED) + { + NMLOG_WARNING("WiFiSignalStrengthChanged to disconnect - WifiSignalStrengthMonitor exiting"); + stopThread= false; + break; // Let the thread exit naturally + } + } + else + NMLOG_FATAL("NetworkManagerImplementation pointer error !"); + // Wait for the specified interval or until notified to stop + std::this_thread::sleep_for(std::chrono::seconds(interval)); + } + isRunning = false; + } + } +} \ No newline at end of file diff --git a/NetworkManager/service/WifiSignalStrengthMonitor.h b/NetworkManager/service/WifiSignalStrengthMonitor.h new file mode 100644 index 0000000000..19f757b49a --- /dev/null +++ b/NetworkManager/service/WifiSignalStrengthMonitor.h @@ -0,0 +1,50 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2020 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include "Module.h" +#include "NetworkManagerLogger.h" + +#define DEFAULT_WIFI_SIGNAL_TEST_INTERVAL_SEC 60 +namespace WPEFramework +{ + namespace Plugin + { + class WifiSignalStrengthMonitor + { + public: + WifiSignalStrengthMonitor():isRunning(false) {} + ~WifiSignalStrengthMonitor(){ NMLOG_INFO("~WifiSignalStrengthMonitor"); } + void startWifiSignalStrengthMonitor(int interval); + void getSignalData(std::string &ssid, Exchange::INetworkManager::WiFiSignalQuality &quality, std::string &strengthOut); + private: + std::string retrieveValues(const char *command, const char* keyword, char *output_buffer, size_t output_buffer_size); + std::thread monitorThread; + std::atomic stopThread; + std::atomic isRunning; + void monitorThreadFunction(int interval); + }; + } +} \ No newline at end of file