Skip to content
Open
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ option(ENABLE_LEGACY_PLUGINS "Enable Legacy Plugins" ON)
option(USE_RDK_LOGGER "Enable RDK Logger for logging" OFF )
option(ENABLE_UNIT_TESTING "Enable unit tests" OFF)
option(USE_TELEMETRY "Enable Telemetry T2 support" OFF)
option(USE_CONNECTIVITYCHECKMGR "Enable ConnectivityCheckMgr delegation (compiles the delegation client and reads the TR-181 RFC feature flag via rfcapi)" OFF)
option(ENABLE_ETHERNET_CONNECTION_HANDLING
"Enable pre-sleep Ethernet deactivation" OFF)

Expand All @@ -77,6 +78,16 @@ if (USE_TELEMETRY)
message("Telemetry support enabled")
endif(USE_TELEMETRY)

# Optional ConnectivityCheckMgr delegation. Compiles the delegation client and pulls
# in the rfcapi library used to read the TR-181 RFC feature flag at runtime, e.g.
# Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.ConnectivityCheckMgr.Enable.
if (USE_CONNECTIVITYCHECKMGR)
find_library(RFCAPI_LIBRARY rfcapi REQUIRED)
find_path(RFCAPI_INCLUDE_DIR rfcapi.h)
add_compile_definitions(USE_CONNECTIVITYCHECKMGR=1)
message(STATUS "ConnectivityCheckMgr delegation enabled (rfcapi lib=${RFCAPI_LIBRARY}, include=${RFCAPI_INCLUDE_DIR})")
endif(USE_CONNECTIVITYCHECKMGR)

add_subdirectory(interface)
add_subdirectory(definition)
add_subdirectory(plugin)
Expand Down
30 changes: 30 additions & 0 deletions definition/NetworkManager.json
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,36 @@
]
}
},
"onRouteChange":{
"summary": "Triggered when the default route changes and a new gateway/DNS becomes available for an interface.",
"params": {
"type": "object",
"properties": {
"interface":{
"$ref": "#/definitions/interface"
},
"ipversion": {
"$ref": "#/definitions/ipversion"
},
"ipaddress": {
"$ref": "#/definitions/ipaddress"
},
"gateway": {
"$ref": "#/definitions/gateway"
},
"primarydns": {
"$ref": "#/definitions/primarydns"
}
},
"required": [
"interface",
"ipversion",
"ipaddress",
"gateway",
"primarydns"
]
}
},
"onActiveInterfaceChange":{
"summary": "Triggered when the primary/active interface changes",
"params": {
Expand Down
33 changes: 33 additions & 0 deletions docs/NetworkManagerPlugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -1787,6 +1787,7 @@ NetworkManager interface events:
| :-------- | :-------- |
| [onInterfaceStateChange](#event.onInterfaceStateChange) | Triggered when an interface state is changed |
| [onAddressChange](#event.onAddressChange) | Triggered when an IP Address is assigned or lost |
| [onRouteChange](#event.onRouteChange) | Triggered when the default route changes and a new gateway/DNS becomes available for an interface |
| [onActiveInterfaceChange](#event.onActiveInterfaceChange) | Triggered when the primary/active interface changes |
| [onInternetStatusChange](#event.onInternetStatusChange) | Triggered when internet connection state changed |
| [onAvailableSSIDs](#event.onAvailableSSIDs) | Triggered when scan completes or when scan cancelled |
Expand Down Expand Up @@ -1858,6 +1859,38 @@ Triggered when an IP Address is assigned or lost.
}
```

<a name="event.onRouteChange"></a>
## *onRouteChange [<sup>event</sup>](#head.Notifications)*

Triggered when the default route changes and a new gateway/DNS becomes available for an interface.

### Parameters

| Name | Type | Description |
| :-------- | :-------- | :-------- |
| params | object | |
| params.interface | string | An interface, such as `eth0` or `wlan0`, depending upon availability of the given interface |
| params.ipversion | string | Either IPv4 or IPv6 |
| params.ipaddress | string | The IP address |
| params.gateway | string | The gateway address |
| params.primarydns | string | The primary DNS address |

### Example

```json
{
"jsonrpc": "2.0",
"method": "client.events.1.onRouteChange",
"params": {
"interface": "wlan0",
"ipversion": "IPv4",
"ipaddress": "192.168.1.101",
"gateway": "192.168.1.1",
"primarydns": "192.168.1.1"
}
}
```

<a name="event.onActiveInterfaceChange"></a>
## *onActiveInterfaceChange [<sup>event</sup>](#head.Notifications)*

Expand Down
1 change: 1 addition & 0 deletions interface/INetworkManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ namespace WPEFramework
virtual void onInterfaceStateChange(const InterfaceState state /* @in */, const string interface /* @in */){};
virtual void onActiveInterfaceChange(const string prevActiveInterface /* @in */, const string currentActiveInterface /* @in */){};
virtual void onIPAddressChange(const string interface /* @in */, const string ipversion /* @in */, const string ipaddress /* @in */, const IPStatus status /* @in */){};
virtual void onRouteChange(const string interface /* @in */, const string ipversion /* @in */, const string ipaddress /* @in */, const string gateway /* @in */, const string primarydns /* @in */){};
virtual void onInternetStatusChange(const InternetStatus prevState /* @in */, const InternetStatus currState /* @in */, const string interface /* @in */){};
Comment on lines 282 to 286

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved


// WiFi Notifications that other processes can subscribe to
Expand Down
22 changes: 21 additions & 1 deletion plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ endif ()

set(PLUGIN_NETWORKMANAGER_LOGLEVEL "3" CACHE STRING "To configure default loglevel NetworkManager plugin")
set(PLUGIN_NETWORKMANAGER_STARTUPORDER "25" CACHE STRING "To configure startup order of Unified NetworkManager plugin")
set(PLUGIN_NETWORKMANAGER_USE_CONNECTIVITYCHECKMGR "false" CACHE STRING "Config fallback to delegate connectivity to ConnectivityCheckMgr when the RFC flag is unset")

set(PLUGIN_NETWORKMANAGER_AUTOSTART "false" CACHE STRING "Set the default AutoStart of NetworkManager Plugin")
set(PLUGIN_BUILD_REFERENCE ${PROJECT_VERSION} CACHE STRING "To Set the Hash for the plugin")
Expand Down Expand Up @@ -79,12 +80,31 @@ set_target_properties(${MODULE_NAME} PROPERTIES

add_library(${MODULE_IMPL_NAME} SHARED
NetworkManagerImplementation.cpp
NetworkManagerConnectivity.cpp
NetworkManagerStunClient.cpp
NetworkManagerLogger.cpp
NetworkManagerPowerClient.cpp
Module.cpp)

# The built-in ConnectivityMonitor is always compiled. The ConnectivityCheckMgr
# delegation client (NetworkManagerConnectivityClient.cpp) is compiled only when
# USE_CONNECTIVITYCHECKMGR is enabled; runtime selection between the two backends
# is done in resolveConnectivityCheckMgrEnabled(). STUN is unaffected either way.
target_sources(${MODULE_IMPL_NAME} PRIVATE
NetworkManagerConnectivity.cpp)

# Optional ConnectivityCheckMgr delegation. The USE_CONNECTIVITYCHECKMGR option,
# rfcapi library discovery, and the USE_CONNECTIVITYCHECKMGR compile definition are
# declared in the top-level CMakeLists.txt (mirroring USE_TELEMETRY). When enabled we
# compile the delegation client and link the rfcapi library used to read the TR-181
# feature flag.
if(USE_CONNECTIVITYCHECKMGR)
target_sources(${MODULE_IMPL_NAME} PRIVATE NetworkManagerConnectivityClient.cpp)
target_link_libraries(${MODULE_IMPL_NAME} PRIVATE ${RFCAPI_LIBRARY})
if(RFCAPI_INCLUDE_DIR)
target_include_directories(${MODULE_IMPL_NAME} PRIVATE ${RFCAPI_INCLUDE_DIR})
endif()
endif()

if(ENABLE_GNOME_NETWORKMANAGER)
if(ENABLE_GNOME_GDBUS)
message("networkmanager building with gdbus")
Expand Down
1 change: 1 addition & 0 deletions plugin/NetworkManager.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ configuration.add("root", process)
configuration.add("connectivity", connectivity)
configuration.add("stun", stun)
configuration.add("loglevel", "@PLUGIN_NETWORKMANAGER_LOGLEVEL@")
configuration.add("useConnectivityCheckMgr", "@PLUGIN_NETWORKMANAGER_USE_CONNECTIVITYCHECKMGR@")

6 changes: 6 additions & 0 deletions plugin/NetworkManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ namespace WPEFramework
_parent.onIPAddressChange(interface, ipversion, ipaddress, status);
}

void onRouteChange(const string interface, const string ipversion, const string ipaddress, const string gateway, const string primarydns) override
{
_parent.onRouteChange(interface, ipversion, ipaddress, gateway, primarydns);
}

void onInternetStatusChange(const Exchange::INetworkManager::InternetStatus prevState, const Exchange::INetworkManager::InternetStatus currState, const string interface) override
{
_parent.onInternetStatusChange(prevState, currState, interface);
Expand Down Expand Up @@ -260,6 +265,7 @@ namespace WPEFramework
void onInterfaceStateChange(const Exchange::INetworkManager::InterfaceState state, const string interface);
void onActiveInterfaceChange(const string prevActiveInterface, const string currentActiveinterface);
void onIPAddressChange(const string interface, const string ipversion, const string ipaddress, const Exchange::INetworkManager::IPStatus status);
void onRouteChange(const string interface, const string ipversion, const string ipaddress, const string gateway, const string primarydns);
void onInternetStatusChange(const Exchange::INetworkManager::InternetStatus prevState, const Exchange::INetworkManager::InternetStatus currState, const string interface);
void onAvailableSSIDs(const string jsonOfScanResults);
void onWiFiStateChange(const Exchange::INetworkManager::WiFiState state);
Expand Down
190 changes: 190 additions & 0 deletions plugin/NetworkManagerConnectivityClient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/**
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
* Copyright 2026 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 "NetworkManagerConnectivityClient.h"
#include "NetworkManagerLogger.h"
#include <com/com.h>

using namespace WPEFramework;
using namespace WPEFramework::Exchange;
using namespace WPEFramework::Plugin;

// ---------------------------------------------------------------------------
// NetworkManagerConnectivityClient
// ---------------------------------------------------------------------------

NetworkManagerConnectivityClient::NetworkManagerConnectivityClient()
: mNotification(*this)
{
NMLOG_INFO("connecting to ConnectivityCheckMgr");
if (auto r = Open(RPC::CommunicationTimeOut, Connector(), "org.rdk.ConnectivityCheckMgr"); r == Core::ERROR_NONE) {
// Connected; Operational() will be called by the framework when the proxy is ready.
} else {
NMLOG_ERROR("failed to open link to ConnectivityCheckMgr (error %u)", r);
}
}

NetworkManagerConnectivityClient::~NetworkManagerConnectivityClient()
{
NMLOG_INFO("shutting down");
{
std::lock_guard<std::mutex> lock(mLock);
unregisterEvents();
if (mConnectivity != nullptr) {
mConnectivity->Release();
mConnectivity = nullptr;
}
}
Close(Core::infinite);
}

bool NetworkManagerConnectivityClient::IsValid() const
{
LOG_ENTRY_FUNCTION();
std::lock_guard<std::mutex> lock(mLock);
return mConnectivity != nullptr;
}

void NetworkManagerConnectivityClient::Operational(bool upAndRunning)
{
NMLOG_DEBUG("Operational(%s)", upAndRunning ? "true" : "false");
std::lock_guard<std::mutex> lock(mLock);
if (upAndRunning) {
if (mConnectivity == nullptr) {
mConnectivity = Interface();
registerEvents();
}
} else {
unregisterEvents();
if (mConnectivity != nullptr) {
mConnectivity->Release();
mConnectivity = nullptr;
}
}
}

void NetworkManagerConnectivityClient::SetInternetStatusChangeHandler(InternetStatusChangeHandler handler)
{
std::lock_guard<std::mutex> lock(mLock);
mInternetStatusChangeHandler = std::move(handler);
}

void NetworkManagerConnectivityClient::registerEvents()
{
if (mConnectivity == nullptr) {
return;
}
if (mNotificationRegistered) {
return;
}

if (auto r = mConnectivity->Register(&mNotification); r != Core::ERROR_NONE) {
NMLOG_ERROR("ConnectivityCheckMgr register(notification) failed (%u)", r);
return;
}

mNotificationRegistered = true;
NMLOG_INFO("registered for ConnectivityCheckMgr internet-status notifications");
}

void NetworkManagerConnectivityClient::unregisterEvents()
{
if (mConnectivity == nullptr) {
mNotificationRegistered = false;
return;
}
if (!mNotificationRegistered) {
return;
}

if (auto r = mConnectivity->Unregister(&mNotification); r != Core::ERROR_NONE) {
NMLOG_ERROR("ConnectivityCheckMgr unregister(notification) failed (%u)", r);
}
mNotificationRegistered = false;
}

void NetworkManagerConnectivityClient::notifyInternetStatusChanged(Exchange::IConnectivityCheck::InternetStatus status)
{
InternetStatusChangeHandler handler;
{
std::lock_guard<std::mutex> lock(mLock);
handler = mInternetStatusChangeHandler;
}

if (!handler) {
return;
}

handler(mapStatus(status));
}

void NetworkManagerConnectivityClient::Notification::OnInternetStatusChange(
const Exchange::IConnectivityCheck::InternetStatus status,
const string& reason)
{
(void)reason;
mParent.notifyInternetStatusChanged(status);
}

NetworkManagerConnectivityClient::NmInternetStatus
NetworkManagerConnectivityClient::mapStatus(Exchange::IConnectivityCheck::InternetStatus status)
{
switch (status) {
case Exchange::IConnectivityCheck::NO_INTERNET: return Exchange::INetworkManager::INTERNET_NOT_AVAILABLE;
case Exchange::IConnectivityCheck::LIMITED_INTERNET: return Exchange::INetworkManager::INTERNET_LIMITED;
case Exchange::IConnectivityCheck::CAPTIVE_PORTAL: return Exchange::INetworkManager::INTERNET_CAPTIVE_PORTAL;
case Exchange::IConnectivityCheck::FULLY_CONNECTED: return Exchange::INetworkManager::INTERNET_FULLY_CONNECTED;
case Exchange::IConnectivityCheck::UNKNOWN:
default: return Exchange::INetworkManager::INTERNET_UNKNOWN;
}
}

NetworkManagerConnectivityClient::NmInternetStatus
NetworkManagerConnectivityClient::getInternetState()
{
LOG_ENTRY_FUNCTION();
std::lock_guard<std::mutex> lock(mLock);
if (mConnectivity == nullptr) {
NMLOG_WARNING("ConnectivityCheckMgr not available; returning INTERNET_UNKNOWN");
return Exchange::INetworkManager::INTERNET_UNKNOWN;
}

Exchange::IConnectivityCheck::StatusInfo info{};
if (auto r = mConnectivity->GetInternetStatus(info); r != Core::ERROR_NONE) {
NMLOG_ERROR("ConnectivityCheckMgr GetInternetStatus failed (%u)", r);
return Exchange::INetworkManager::INTERNET_UNKNOWN;
}
return mapStatus(info.status);
}

std::string NetworkManagerConnectivityClient::getCaptivePortalURI()
{
LOG_ENTRY_FUNCTION();
std::lock_guard<std::mutex> lock(mLock);
std::string uri;
if (mConnectivity == nullptr) {
NMLOG_WARNING("ConnectivityCheckMgr not available; returning empty captive-portal URI");
return uri;
}
if (auto r = mConnectivity->GetCaptivePortalURI(uri); r != Core::ERROR_NONE) {
NMLOG_ERROR("ConnectivityCheckMgr GetCaptivePortalURI failed (%u)", r);
uri.clear();
}
return uri;
}
Loading
Loading