summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-05-15 11:36:28 +0200
committerThomas Haller <thaller@redhat.com>2015-06-05 12:38:29 +0200
commitdc0193ac023e30a9a3794e78c66f8c5266695a60 (patch)
tree2017276f2bec76590e38c9552e3030005fcef543 /src
parentf031b926c452aea5a28390eee2cfb9b9f0d15652 (diff)
config: support a [connection] section to NetworkManager.conf to specify connection defaults
Add support for a new section [connection] in NetworkManager.conf. If the connection leaves an option at "unknown"/"default", we can support overwriting the value from global configuration. We also support other sections that are named with "connection" as a prefix, such as [connection2], [connection-wifi]. This is to support multiple default values that can be applied depending on the used device. I think this has great potential. Only downside is that when the user looks at a connection value, it will see that it is unspecified. But the actually used value depends on the device type and might not be obvious. https://bugzilla.gnome.org/show_bug.cgi?id=695383 https://bugzilla.redhat.com/show_bug.cgi?id=1164677
Diffstat (limited to 'src')
-rw-r--r--src/nm-config-data.c122
-rw-r--r--src/nm-config-data.h4
-rw-r--r--src/tests/config/NetworkManager.conf24
-rw-r--r--src/tests/config/test-config.c51
4 files changed, 201 insertions, 0 deletions
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index 41995a043..73c36312f 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -27,6 +27,19 @@
#include "gsystem-local-alloc.h"
#include "nm-device.h"
#include "nm-core-internal.h"
+#include "nm-macros-internal.h"
+
+typedef struct {
+ char *group_name;
+ gboolean stop_match;
+ struct {
+ /* have a separate boolean field @has, because a @spec with
+ * value %NULL does not necessarily mean, that the property
+ * "match-device" was unspecified. */
+ gboolean has;
+ GSList *spec;
+ } match_device;
+} ConnectionInfo;
typedef struct {
char *config_main_file;
@@ -34,6 +47,10 @@ typedef struct {
GKeyFile *keyfile;
+ /* A zero-terminated list of pre-processed information from the
+ * [connection] sections. This is to speed up lookup. */
+ ConnectionInfo *connection_infos;
+
struct {
char *uri;
char *response;
@@ -172,6 +189,100 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic
/************************************************************************/
+char *
+nm_config_data_get_connection_default (const NMConfigData *self,
+ const char *property,
+ NMDevice *device)
+{
+ NMConfigDataPrivate *priv;
+ const ConnectionInfo *connection_info;
+
+ g_return_val_if_fail (self, NULL);
+ g_return_val_if_fail (property && *property, NULL);
+ g_return_val_if_fail (strchr (property, '.'), NULL);
+
+ priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+
+ if (!priv->connection_infos)
+ return NULL;
+
+ for (connection_info = &priv->connection_infos[0]; connection_info->group_name; connection_info++) {
+ char *value;
+ gboolean match;
+
+ value = g_key_file_get_value (priv->keyfile, connection_info->group_name, property, NULL);
+ if (!value && !connection_info->stop_match)
+ continue;
+
+ match = TRUE;
+ if (connection_info->match_device.has)
+ match = device && nm_device_spec_match_list (device, connection_info->match_device.spec);
+
+ if (match)
+ return value;
+ g_free (value);
+ }
+ return NULL;
+}
+
+static ConnectionInfo *
+_get_connection_infos (GKeyFile *keyfile)
+{
+ char **groups;
+ guint i;
+ char *connection_tag = NULL;
+ GSList *connection_groups = NULL;
+ ConnectionInfo *connection_infos = NULL;
+
+ /* get the list of existing [connection.\+] sections that we consider
+ * for nm_config_data_get_connection_default(). Also, get them
+ * in the right order. */
+ groups = g_key_file_get_groups (keyfile, NULL);
+ for (i = 0; groups && groups[i]; i++) {
+ if (g_str_has_prefix (groups[i], "connection")) {
+ if (strlen (groups[i]) == STRLEN ("connection"))
+ connection_tag = groups[i];
+ else
+ connection_groups = g_slist_prepend (connection_groups, groups[i]);
+ } else
+ g_free (groups[i]);
+ }
+ g_free (groups);
+ if (connection_tag) {
+ /* We want the group "connection" checked at last, so that
+ * all other "connection.\+" have preference. Those other
+ * groups are checked in order of appearance. */
+ connection_groups = g_slist_prepend (connection_groups, connection_tag);
+ }
+ if (connection_groups) {
+ guint len = g_slist_length (connection_groups);
+ GSList *iter;
+
+ connection_infos = g_new0 (ConnectionInfo, len + 1);
+ for (iter = connection_groups; iter; iter = iter->next) {
+ ConnectionInfo *connection_info;
+ char *value;
+
+ nm_assert (len >= 1);
+ connection_info = &connection_infos[--len];
+ connection_info->group_name = iter->data;
+
+ value = g_key_file_get_value (keyfile, iter->data, "match-device", NULL);
+ if (value) {
+ connection_info->match_device.has = TRUE;
+ connection_info->match_device.spec = nm_match_spec_split (value);
+ g_free (value);
+ }
+ connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, iter->data, "stop-match", FALSE);
+ }
+ g_slist_free (connection_groups);
+ }
+
+ return connection_infos;
+}
+
+/************************************************************************/
+
static gboolean
_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b)
{
@@ -324,6 +435,7 @@ static void
finalize (GObject *gobject)
{
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject);
+ guint i;
g_free (priv->config_main_file);
g_free (priv->config_description);
@@ -340,6 +452,14 @@ finalize (GObject *gobject)
g_slist_free_full (priv->ignore_carrier, g_free);
g_slist_free_full (priv->assume_ipv6ll_only, g_free);
+ if (priv->connection_infos) {
+ for (i = 0; priv->connection_infos[i].group_name; i++) {
+ g_free (priv->connection_infos[i].group_name);
+ g_slist_free_full (priv->connection_infos[i].match_device.spec, g_free);
+ }
+ g_free (priv->connection_infos);
+ }
+
g_key_file_unref (priv->keyfile);
G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject);
@@ -357,6 +477,8 @@ constructed (GObject *object)
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self);
char *interval;
+ priv->connection_infos = _get_connection_infos (priv->keyfile);
+
priv->connectivity.uri = g_key_file_get_value (priv->keyfile, "connectivity", "uri", NULL);
priv->connectivity.response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL);
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index a8182f283..78b04ec8c 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -94,6 +94,10 @@ const char *nm_config_data_get_rc_manager (const NMConfigData *self);
gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device);
gboolean nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *device);
+char *nm_config_data_get_connection_default (const NMConfigData *self,
+ const char *property,
+ NMDevice *device);
+
G_END_DECLS
#endif /* NM_CONFIG_DATA_H */
diff --git a/src/tests/config/NetworkManager.conf b/src/tests/config/NetworkManager.conf
index 401ba48a7..36113661f 100644
--- a/src/tests/config/NetworkManager.conf
+++ b/src/tests/config/NetworkManager.conf
@@ -13,3 +13,27 @@ response=Hello
[extra-section]
extra-key=some value
+
+
+
+[connection]
+ipv4.route-metric=50
+ipv6.ip6_privacy=0
+dummy.test1=no
+dummy.test2=no
+
+[connection.dev51]
+match-device=mac:00:00:00:00:00:51
+stop-match=yes
+ipv4.route-metric=51
+dummy.test1=yes
+
+[connection.dev52]
+match-device=mac:00:00:00:00:00:52
+ipv4.route-metric=52
+
+[connection.public]
+match-device=interface-name:wlan1
+# match-wifi is not yet implemented. Just an idea what could be useful.
+match-wifi=ssid:*[Ss]tarbucks*|*University*
+ipv6.ip6_privacy=2
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index f4d72d333..4a23f23fe 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -94,6 +94,9 @@ test_config_simple (void)
GError *error = NULL;
const char **plugins;
char *value;
+ gs_unref_object NMDevice *dev50 = nm_test_device_new ("00:00:00:00:00:50");
+ gs_unref_object NMDevice *dev51 = nm_test_device_new ("00:00:00:00:00:51");
+ gs_unref_object NMDevice *dev52 = nm_test_device_new ("00:00:00:00:00:52");
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL);
@@ -122,6 +125,54 @@ test_config_simple (void)
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND);
g_clear_error (&error);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "connection", "ipv6.ip6_privacy", NULL);
+ g_assert_cmpstr (value, ==, "0");
+ g_free (value);
+
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "connection.dev51", "ipv4.route-metric", NULL);
+ g_assert_cmpstr (value, ==, "51");
+ g_free (value);
+
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv6.route-metric", NULL);
+ g_assert_cmpstr (value, ==, NULL);
+ g_free (value);
+
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", NULL);
+ g_assert_cmpstr (value, ==, "50");
+ g_free (value);
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev50);
+ g_assert_cmpstr (value, ==, "50");
+ g_free (value);
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev51);
+ g_assert_cmpstr (value, ==, "51");
+ g_free (value);
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev52);
+ g_assert_cmpstr (value, ==, "52");
+ g_free (value);
+
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test1", dev51);
+ g_assert_cmpstr (value, ==, "yes");
+ g_free (value);
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test1", dev50);
+ g_assert_cmpstr (value, ==, "no");
+ g_free (value);
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test2", dev51);
+ g_assert_cmpstr (value, ==, NULL);
+ g_free (value);
+
+ value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test2", dev50);
+ g_assert_cmpstr (value, ==, "no");
+ g_free (value);
+
+
g_object_unref (config);
}