Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
123 changes: 123 additions & 0 deletions plugin/NetworkManagerConnectivityClient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* 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()
{
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);
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();
}
} else {
if (mConnectivity != nullptr) {
mConnectivity->Release();
mConnectivity = nullptr;
}
}
}

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;
}
84 changes: 84 additions & 0 deletions plugin/NetworkManagerConnectivityClient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* 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.
**/

#pragma once

#include "Module.h"
#include "INetworkManager.h"
#include <interfaces/IConnectivityCheck.h>
#include <mutex>
#include <string>

namespace WPEFramework {
namespace Plugin {

/**
* COM-RPC client that delegates internet-connectivity queries to the
* ConnectivityCheckMgr plugin (org.rdk.ConnectivityCheckMgr).
*
* Because the delegation lives in the out-of-process implementation, both the
* JSON-RPC surface (shell -> implementation) and direct COM-RPC callers of
* INetworkManager::IsConnectedToInternet / GetCaptivePortalURI are served
* consistently.
*
* Mirrors NetworkManagerPowerClient:
* - Inherits SmartInterfaceType<IConnectivityCheck> for automatic
* connect / reconnect and Operational() lifecycle callbacks.
*
* Lifecycle:
* Construction -> Open() connects to ConnectivityCheckMgr (async).
* Operational(true) -> acquires the proxy; IsValid() returns true.
* Operational(false) -> releases the proxy.
* Destruction -> Close().
*
* All queries fall back to INTERNET_UNKNOWN / empty when the plugin is not
* available, so callers never crash on a boot-order race or NM/CCM restart.
*/
class NetworkManagerConnectivityClient : protected RPC::SmartInterfaceType<Exchange::IConnectivityCheck> {
public:
using NmInternetStatus = Exchange::INetworkManager::InternetStatus;

NetworkManagerConnectivityClient();
~NetworkManagerConnectivityClient() override;

NetworkManagerConnectivityClient(const NetworkManagerConnectivityClient&) = delete;
NetworkManagerConnectivityClient& operator=(const NetworkManagerConnectivityClient&) = delete;

/** Returns true when the ConnectivityCheckMgr COMRPC proxy is available. */
bool IsValid() const;

/** Delegated internet status, mapped to NetworkManager's InternetStatus. */
NmInternetStatus getInternetState();

/** Delegated captive-portal URI (empty when unavailable / not captive). */
std::string getCaptivePortalURI();

private:
// SmartInterfaceType lifecycle callback.
void Operational(bool upAndRunning) override;

// 1:1 mapping ConnectivityCheckMgr InternetStatus -> NetworkManager InternetStatus.
static NmInternetStatus mapStatus(Exchange::IConnectivityCheck::InternetStatus status);

mutable std::mutex mLock;
Exchange::IConnectivityCheck* mConnectivity{nullptr};
};

} // namespace Plugin
} // namespace WPEFramework
Loading
Loading