[PATCH v2] manager: add support for changing 'PreferredTechnologies' over DBus

Alexandru Ardelean <[email protected]>
Newsgroups dev.linux.lists.connman
Message-ID <[email protected]>
This change adds support for reading/modifying the 'PreferredTechnologies'
over DBus.
This can be extended to 'DefaultAutoConnectTechnologies',
'DefaultFavoriteTechnologies' & 'AlwaysConnectedTechnologies' as well.
However the interest (so far) was in changing the 'PreferredTechnologies'
order (at runtime) between cellular and wifi.
Also, 'PreferredTechnologies' was the only that was tested.

Changing 'PreferredTechnologies' seems to yield the desired result, as the
switch between cellular/wifi does not need to be super-fast.
And it changes the routing table (as desired) when cellular is preferred
over WiFi (and vice-versa).

On some boxes that have both cellular & WiFi, it's often desired to prefer
cellular (over WiFi) in case WiFi is not able to connect to the internet.
The logic (for this switching) can be determined outside of connman.
Setting 'PreferredTechnologies' helps in this case.
---

Changelog v1 -> v2:
* v1: https://lore.kernel.org/connman/[email protected]/
* removed 'tools/ip6tables-test'
  * added to .gitignore via https://lore.kernel.org/connman/[email protected]/T/#u
* added a bit of documentation in 'src/main.conf' for the 'PreferredTechnologies'
  property now also being accessible over DBus

 doc/connman.conf.5.in |  2 ++
 doc/manager-api.txt   | 13 +++++++++
 include/setting.h     |  2 ++
 src/main.c            | 22 ++++++++++++++
 src/main.conf         |  4 +++
 src/manager.c         | 67 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 110 insertions(+)

diff --git a/doc/connman.conf.5.in b/doc/connman.conf.5.in
index 3eb240f5..c8ce8eb6 100644
--- a/doc/connman.conf.5.in
+++ b/doc/connman.conf.5.in
@@ -101,6 +101,8 @@ with state 'ready' or with a non-preferred type; a service
 of a preferred technology type in state 'online' will get
 the default route when compared to either a non-preferred
 type or a preferred type further down in the list.
+This property can be read and set over DBus as well, on
+the 'net.connman.Manager' DBus interface.
 .TP
 .BI NetworkInterfaceBlacklist= interface\fR[,...]
 List of blacklisted network interfaces separated by ",".
diff --git a/doc/manager-api.txt b/doc/manager-api.txt
index 6eaa0a38..3be9cffc 100644
--- a/doc/manager-api.txt
+++ b/doc/manager-api.txt
@@ -319,3 +319,16 @@ Properties	string State [readonly]
 			and does not affect ConnMan in any way.
 
 			The default value is false.
+
+		array{string} PreferredTechnologies [readwrite] [experminental]
+
+			This property is the same one that is defined in
+			/etc/connman/main.conf. It controls the order of
+			preferred technologies (e.g. wifi, cellular) at
+			runtime.
+			Changing it here will not have an immediate effect.
+			It's only when connman gets triggered via service changes
+			that this gets taken into consideration. Or, when it's
+			triggered via manual connect/disconnect of services.
+
+			The default value is defined in /etc/connman/main.conf.
diff --git a/include/setting.h b/include/setting.h
index 920e6754..6a575dc4 100644
--- a/include/setting.h
+++ b/include/setting.h
@@ -33,6 +33,8 @@ unsigned int connman_setting_get_uint(const char *key);
 char *connman_setting_get_string(const char *key);
 char **connman_setting_get_string_list(const char *key);
 unsigned int *connman_setting_get_uint_list(const char *key);
+int connman_setting_set_uint_list(const char *key, const unsigned int *lst,
+                                  int len);
 
 unsigned int connman_timeout_input_request(void);
 unsigned int connman_timeout_browser_launch(void);
diff --git a/src/main.c b/src/main.c
index f5da979b..7858b967 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1122,6 +1122,28 @@ unsigned int *connman_setting_get_uint_list(const char *key)
 	return NULL;
 }
 
+int connman_setting_set_uint_list(const char *key, const unsigned int *lst,
+				  int len)
+{
+	unsigned int *new_list;
+
+	new_list = g_try_new0(unsigned int, len + 1);
+	if (!new_list)
+		return -1;
+
+	memcpy(new_list, lst, sizeof(unsigned int) * len);
+
+	if (g_str_equal(key, CONF_PREFERRED_TECHS)) {
+		g_free(connman_settings.preferred_techs);
+		connman_settings.preferred_techs = new_list;
+		return 0;
+	}
+
+	g_free(new_list);
+
+	return -1;
+}
+
 unsigned int connman_timeout_input_request(void)
 {
 	return connman_settings.timeout_inputreq;
diff --git a/src/main.conf b/src/main.conf
index 5357edb8..80b4fb83 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -60,6 +60,10 @@
 # of a preferred technology type in state 'online' will get
 # the default route when compared to either a non-preferred
 # type or a preferred type further down in the list.
+# This property is also configurable via DBus through the
+# 'net.connman.Manager' & SetProperty method.
+# The GetProperties DBus method will list this property
+# and its current value.
 # PreferredTechnologies =
 
 # List of blacklisted network interfaces separated by ",".
diff --git a/src/manager.c b/src/manager.c
index 892d3a42..62f34c50 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -34,6 +34,27 @@
 static bool connman_state_idle;
 static dbus_bool_t sessionmode;
 
+static const char *tech_property_names[] = {
+	"PreferredTechnologies",
+	NULL,
+};
+
+static void append_tech_list(DBusMessageIter *iter, void *user_data)
+{
+	unsigned int *tech_list = user_data;
+	int i;
+
+	if (!tech_list)
+		return;
+
+	for (i = 0; tech_list[i]; i++) {
+		const char *s = __connman_service_type2string(tech_list[i]);
+		if (!s)
+			continue;
+		dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
+	}
+}
+
 static DBusMessage *get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -41,6 +62,7 @@ static DBusMessage *get_properties(DBusConnection *conn,
 	DBusMessageIter array, dict;
 	dbus_bool_t offlinemode;
 	const char *str;
+	int i;
 
 	DBG("conn %p", conn);
 
@@ -64,6 +86,13 @@ static DBusMessage *get_properties(DBusConnection *conn,
 					DBUS_TYPE_BOOLEAN,
 					&sessionmode);
 
+	for (i = 0; tech_property_names[i]; i++) {
+		const char *name = tech_property_names[i];
+		unsigned int *lst = connman_setting_get_uint_list(name);
+		connman_dbus_dict_append_array(&dict, name, DBUS_TYPE_STRING,
+						append_tech_list, lst);
+	}
+
 	connman_dbus_dict_close(&array, &dict);
 
 	return reply;
@@ -110,6 +139,44 @@ static DBusMessage *set_property(DBusConnection *conn,
 
 		dbus_message_iter_get_basic(&value, &sessionmode);
 
+	} else if (g_str_equal(name, "PreferredTechnologies")) {
+		unsigned int techs[MAX_CONNMAN_SERVICE_TYPES] = {};
+		DBusMessageIter entry;
+		int cnt;
+
+		if (type != DBUS_TYPE_ARRAY)
+			return __connman_error_invalid_arguments(msg);
+
+		dbus_message_iter_recurse(&value, &entry);
+
+		cnt = 0;
+		while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+			enum connman_service_type type;
+			const char *val;
+			dbus_message_iter_get_basic(&entry, &val);
+			dbus_message_iter_next(&entry);
+			int i;
+
+			if (!val[0])
+				continue;
+
+			type = __connman_service_string2type(val);
+			if (type == CONNMAN_SERVICE_TYPE_UNKNOWN)
+				return __connman_error_invalid_arguments(msg);
+
+			if (cnt >= MAX_CONNMAN_SERVICE_TYPES)
+				return __connman_error_invalid_arguments(msg);
+
+			/* check for duplicates */
+			for (i = 0; i < cnt; i++) {
+				if (type == techs[i])
+					return __connman_error_invalid_arguments(msg);
+			}
+
+			techs[cnt++] = type;
+		}
+
+		connman_setting_set_uint_list(name, techs, cnt);
 	} else
 		return __connman_error_invalid_property(msg);
 
-- 
2.45.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.