[PATCH v2 34/42] vpn-provider: Make daemonless VPNs to connect when connmand is online

Jussi Laakkonen <[email protected]> Wed, 13 Aug 2025 18:02:06 +0300
Newsgroups dev.linux.lists.connman
Message-ID <[email protected]>
Reformat the connmand status checking code to account the exact online
state. Add a function get_flags for vpn_provider_driver struct to get
the flags set by the plugin to determine whether VPN can be attempted to
connect in ready or online state. Do connect daemonless VPNs only after
connmand reports being online, as they may be connected too early and
network is not setup yet if they get connected when connmand has reached
ready state. Thus, this does not change the functionality for the VPNs
using a daemon.
---
 vpn/vpn-provider.c | 67 +++++++++++++++++++++++++++++++++-------------
 vpn/vpn-provider.h |  1 +
 2 files changed, 50 insertions(+), 18 deletions(-)

diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index 3942c937..b81e3df4 100644
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -125,7 +125,14 @@ static unsigned int get_connman_state_timeout;
 static guint connman_signal_watch;
 static guint connman_service_watch;
 
-static bool connman_online;
+enum connman_state {
+	CONNMAN_IDLE = 0,
+	CONNMAN_OFFLINE,
+	CONNMAN_READY,
+	CONNMAN_ONLINE
+};
+
+static enum connman_state connman_online_state = CONNMAN_IDLE;
 static bool state_query_completed;
 
 
@@ -164,22 +171,46 @@ static void set_state(const char *new_state)
 	if (!new_state || !*new_state)
 		return;
 
-	DBG("old state %s new state %s",
-				connman_online ?
-				CONNMAN_STATE_ONLINE "/" CONNMAN_STATE_READY :
-				CONNMAN_STATE_OFFLINE "/" CONNMAN_STATE_IDLE,
-				new_state);
-
-	/* States "online" and "ready" mean connman is online */
-	if (!g_ascii_strcasecmp(new_state, CONNMAN_STATE_ONLINE) ||
-			!g_ascii_strcasecmp(new_state, CONNMAN_STATE_READY))
-		connman_online = true;
-	/* Everything else means connman is offline */
+	DBG("received %s, old state %d", new_state, connman_online_state);
+
+	if (!g_ascii_strcasecmp(new_state, CONNMAN_STATE_ONLINE))
+		connman_online_state = CONNMAN_ONLINE;
+	else if (!g_ascii_strcasecmp(new_state, CONNMAN_STATE_READY))
+		connman_online_state = CONNMAN_READY;
+	else if (!g_ascii_strcasecmp(new_state, CONNMAN_STATE_OFFLINE))
+		connman_online_state = CONNMAN_OFFLINE;
 	else
-		connman_online = false;
+		connman_online_state = CONNMAN_IDLE;
+
+	DBG("new state %d ", connman_online_state);
+}
+
+static bool is_connman_connected(struct vpn_provider *provider)
+{
+	int flags = 0;
+
+	DBG("provider %p connmand state %d", provider, connman_online_state);
+
+	if (provider && provider->driver && provider->driver->get_flags)
+		flags = provider->driver->get_flags(provider);
 
-	DBG("set state %s connman_online=%s ", new_state,
-				connman_online ? "true" : "false");
+	switch (connman_online_state) {
+	case CONNMAN_IDLE:
+	case CONNMAN_OFFLINE:
+		return false;
+	case CONNMAN_READY:
+		/* VPNs without daemon may require that network is setup. */
+		if (flags & VPN_FLAG_NO_DAEMON) {
+			DBG("daemonless provider, return false in ready");
+			return false;
+		}
+
+		/* fall-through */
+	case CONNMAN_ONLINE:
+		break;
+	}
+
+	return true;
 }
 
 static void free_route(gpointer data)
@@ -832,8 +863,8 @@ static gboolean do_connect_timeout_function(gpointer data)
 
 	DBG("");
 
-	/* Keep in main loop if connman is not online. */
-	if (!connman_online)
+	/* Keep in main loop if connman is not ready for this VPN. */
+	if (!is_connman_connected(provider))
 		return G_SOURCE_CONTINUE;
 
 	provider->do_connect_timeout = 0;
@@ -887,7 +918,7 @@ static DBusMessage *do_connect(DBusConnection *conn, DBusMessage *msg,
 
 	DBG("conn %p provider %p", conn, provider);
 
-	if (!connman_online) {
+	if (!is_connman_connected(provider)) {
 		if (state_query_completed) {
 			DBG("%s not started - ConnMan not online/ready",
 				provider->identifier);
diff --git a/vpn/vpn-provider.h b/vpn/vpn-provider.h
index c7487525..a7ec5109 100644
--- a/vpn/vpn-provider.h
+++ b/vpn/vpn-provider.h
@@ -175,6 +175,7 @@ struct vpn_provider_driver {
 			int *family, unsigned long *idx,
 			enum vpn_provider_route_type *type);
 	bool (*uses_vpn_agent) (struct vpn_provider *provider);
+	int (*get_flags)(struct vpn_provider *provider);
 };
 
 int vpn_provider_driver_register(struct vpn_provider_driver *driver);
-- 
2.39.5