[PATCH 2/3] config: Add FallbackDeviceTypes configuration option

Jussi Laakkonen <[email protected]> Tue, 12 May 2026 18:36:23 +0300
Newsgroups dev.linux.lists.connman
Message-ID <[email protected]>
From: Simo Piiroinen <[email protected]>

In some devices some /sys/class/net/<interface>/uevent files might be
completely missing DEVTYPE information. Heuristics exist for detecting
wifi devices, but everything else is assumed to be ethernet device. Any
other than known device type is ignored with a warning.

For example for rndis interfaces gadget might be more appropriate
device type assumption than ethernet. This can be accomplished by
adding to main.conf, in General section:

FallbackDeviceTypes = rndis0:gadget

Co-authored-by: Jussi Laakkonen <[email protected]>
---
 doc/connman.conf.5.in |  6 +++++
 src/connman.h         |  2 ++
 src/main.c            | 60 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git a/doc/connman.conf.5.in b/doc/connman.conf.5.in
index a81ac7bb..ab0ae5c2 100644
--- a/doc/connman.conf.5.in
+++ b/doc/connman.conf.5.in
@@ -338,6 +338,12 @@ If this option is not set, it tries to write into
 @runstatedir@/connman/resolv.conf and fallbacks to @sysconfdir@/resolv.conf if
 it fails (@runstatedir@/connman does not exist or is not writeable).
 If you do not want to update resolv.conf, you can set /dev/null.
+.TP
+.BI FallbackDeviceTypes= interface:devtype\fR[,...]
+If /sys/class/net/<interface>/uevent does not contain DEVTYPE information,
+heuristics are used to choose between wifi and ethernet device types. If
+neither is appropriate, this setting can be used to provide more suitable
+fallback value - e.g. rndis0:gadget.
 .SH "EXAMPLE"
 The following example configuration disables hostname updates and enables
 ethernet tethering.
diff --git a/src/connman.h b/src/connman.h
index e55be0a2..188f74a0 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -149,6 +149,8 @@ void __connman_log_enable(struct connman_debug_desc *start,
 
 #include <connman/setting.h>
 
+const char *__connman_setting_get_fallback_device_type(const char *interface);
+
 #include <connman/plugin.h>
 
 int __connman_plugin_init(const char *pattern, const char *exclude);
diff --git a/src/main.c b/src/main.c
index 70909264..ddb28276 100644
--- a/src/main.c
+++ b/src/main.c
@@ -136,6 +136,7 @@ static struct {
 	char *localtime;
 	bool regdom_follows_timezone;
 	char *resolv_conf;
+	GHashTable *fallback_device_types;
 } connman_settings  = {
 	.bg_scan = true,
 	.pref_timeservers = NULL,
@@ -173,6 +174,7 @@ static struct {
 	.use_gateways_as_timeservers = false,
 	.localtime = NULL,
 	.resolv_conf = NULL,
+	.fallback_device_types = NULL,
 };
 
 #define CONF_BG_SCAN                    "BackgroundScanning"
@@ -210,6 +212,7 @@ static struct {
 #define CONF_LOCALTIME                  "Localtime"
 #define CONF_REGDOM_FOLLOWS_TIMEZONE    "RegdomFollowsTimezone"
 #define CONF_RESOLV_CONF                "ResolvConf"
+#define CONF_FALLBACK_DEVICE_TYPES      "FallbackDeviceTypes"
 
 static const char *supported_options[] = {
 	CONF_BG_SCAN,
@@ -247,6 +250,7 @@ static const char *supported_options[] = {
 	CONF_LOCALTIME,
 	CONF_REGDOM_FOLLOWS_TIMEZONE,
 	CONF_RESOLV_CONF,
+	CONF_FALLBACK_DEVICE_TYPES,
 	NULL
 };
 
@@ -322,6 +326,39 @@ static char **parse_fallback_nameservers(char **nameservers, gsize len)
 	return servers;
 }
 
+static GHashTable *parse_fallback_device_types(char **devtypes, gsize len)
+{
+	GHashTable *h;
+
+	h = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+	for (gsize i = 0; i < len; ++i) {
+		char **v;
+
+		v = g_strsplit(devtypes[i], ":", 2);
+		if (!v)
+			continue;
+
+		if (v[0] && v[1]) {
+			if (__connman_device_string2type(v[1]) ==
+						CONNMAN_DEVICE_TYPE_UNKNOWN)
+				connman_warn("Invalid FallbackDeviceType in %s",
+								devtypes[i]);
+			else
+				g_hash_table_replace(h, g_strdup(v[0]),
+								g_strdup(v[1]));
+		}
+
+		g_strfreev(v);
+	}
+
+	if (g_hash_table_size(h) > 0)
+		return h;
+
+	g_hash_table_unref(h);
+	return NULL;
+}
+
 static void check_config(GKeyFile *config, const char *file)
 {
 	char **keys;
@@ -851,6 +888,17 @@ static void parse_config(GKeyFile *config, const char *file)
 	g_clear_error(&error);
 
 	online_check_settings_log();
+
+	str_list = __connman_config_get_string_list(config, GENERAL_GROUP,
+			CONF_FALLBACK_DEVICE_TYPES, &len, &error);
+
+	if (!error)
+		connman_settings.fallback_device_types =
+				parse_fallback_device_types(str_list, len);
+
+	g_strfreev(str_list);
+
+	g_clear_error(&error);
 }
 
 static int config_init(const char *file)
@@ -1165,6 +1213,15 @@ unsigned int connman_timeout_browser_launch(void)
 	return connman_settings.timeout_browserlaunch;
 }
 
+const char *__connman_setting_get_fallback_device_type(const char *interface)
+{
+	if (!connman_settings.fallback_device_types)
+		return NULL;
+
+	return g_hash_table_lookup(connman_settings.fallback_device_types,
+			interface);
+}
+
 int main(int argc, char *argv[])
 {
 	GOptionContext *context;
@@ -1347,6 +1404,9 @@ int main(int argc, char *argv[])
 	g_free(connman_settings.online_check_ipv6_url);
 	g_free(connman_settings.localtime);
 
+	if (connman_settings.fallback_device_types)
+		g_hash_table_unref(connman_settings.fallback_device_types);
+
 	g_free(option_debug);
 	g_free(option_wifi);
 
-- 
2.47.3