summaryrefslogtreecommitdiff
path: root/src/nm-config-data.c
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/nm-config-data.c
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/nm-config-data.c')
-rw-r--r--src/nm-config-data.c122
1 files changed, 122 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);