diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2015-06-19 12:15:12 +0200 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2015-06-19 12:15:12 +0200 |
commit | 2f51ba50df8341370ab1f480f9ec6d60cd32ece2 (patch) | |
tree | 29a4eafb9d781f5ed96821e860872971621abef8 | |
parent | 517e9fa0f062e286f893f41770d0562c4baf0c51 (diff) | |
parent | 1468f4edd2b57e5a76c11df2e397d050b0613d82 (diff) |
merge branch 'th/connection-defaults-bgo695383'
- support new [connection] section in NetworkManager.conf
- allow configuring a default value for ipvx.route-metric
- allow configuring a default value for ipv6.ip6-privacy
and read the fallback configuration from sysctl.
https://bugzilla.gnome.org/show_bug.cgi?id=695383
https://bugzilla.gnome.org/show_bug.cgi?id=721200
https://bugzilla.redhat.com/show_bug.cgi?id=1187525
(cherry-picked from commit 18ecf48d7a9d03194db1b65ef46e386284426f89)
-rw-r--r-- | libnm-core/nm-setting-ip6-config.c | 10 | ||||
-rw-r--r-- | libnm/nm-device.c | 3 | ||||
-rw-r--r-- | man/NetworkManager.conf.xml.in | 87 | ||||
-rw-r--r-- | src/NetworkManagerUtils.c | 38 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 1 | ||||
-rw-r--r-- | src/devices/nm-device-generic.c | 9 | ||||
-rw-r--r-- | src/devices/nm-device.c | 193 | ||||
-rw-r--r-- | src/devices/nm-device.h | 3 | ||||
-rw-r--r-- | src/devices/wwan/nm-device-modem.c | 13 | ||||
-rw-r--r-- | src/nm-config-data.c | 122 | ||||
-rw-r--r-- | src/nm-config-data.h | 4 | ||||
-rw-r--r-- | src/nm-config.c | 16 | ||||
-rw-r--r-- | src/nm-config.h | 4 | ||||
-rw-r--r-- | src/tests/config/NetworkManager.conf | 24 | ||||
-rw-r--r-- | src/tests/config/test-config.c | 51 |
15 files changed, 492 insertions, 86 deletions
diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index 29ca551525..7e3ae4d4da 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -504,9 +504,15 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class) * enabled, it makes the kernel generate a temporary IPv6 address in * addition to the public one generated from MAC address via modified * EUI-64. This enhances privacy, but could cause problems in some - * applications, on the other hand. The permitted values are: 0: disabled, - * 1: enabled (prefer public address), 2: enabled (prefer temporary + * applications, on the other hand. The permitted values are: -1: unknown, + * 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary * addresses). + * + * Having a per-connection setting set to "-1" (unknown) means fallback to + * global configuration "ipv6.ip6-privacy". + * + * If also global configuration is unspecified or set to "-1", fallback to read + * "/proc/sys/net/ipv6/conf/default/use_tempaddr". **/ /* ---ifcfg-rh--- * property: ip6-privacy diff --git a/libnm/nm-device.c b/libnm/nm-device.c index e80ac707d8..cd14c0e902 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -979,6 +979,9 @@ nm_device_get_type_description (NMDevice *device) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); const char *desc, *typename; + /* BEWARE: this function should return the same value + * as nm_device_get_type_description() in nm-core. */ + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); if (priv->type_description) diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index 79db1a2de2..fac4616ff6 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -440,6 +440,88 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth </refsect1> <refsect1> + <title><literal>connection</literal> section</title> + <para>This section allows to specify default values for + connections. Not all properties can be overwritten, only a selected + list below. You can have multiple <literal>connection</literal> + sections, by having different sections with a name that all start + with "connection".</para> + <para> + Example: +<programlisting> +[connection] +ipv6.ip6-privacy=0 + +[connection-wifi-wlan0] +match-device=interface-name:wlan0 +ipv4.route-metric=50 + +[connection-wifi-other] +match-device=type:wifi +ipv4.route-metric=55 +ipv6.ip6-privacy=1 +</programlisting> + </para> + + <para> + The sections are considered in order of appearance, with the + exception that the <literal>[connection]</literal> section is always + considered last. In the example above, this order is <literal>[connection-wifi-wlan0]</literal>, + <literal>[connection-wlan-other]</literal>, and <literal>[connection]</literal>. + When checking for a default configuration value, the section are searched until + the requested value is found. + In the example above, "ipv4.route-metric" for wlan0 interface is set to 50, + and for all other Wi-Fi typed interfaces to 55. Also, Wi-Fi devices would have + IPv6 private addresses enabled by default, but other devices would have it disabled. + Note that also "wlan0" gets "ipv6.ip6-privacy=1", because although the section + "[connection-wifi-wlan0]" matches the device, it does not contain that property + and the search continues. + </para> + + <para> + <variablelist> + <varlistentry> + <term><varname>match-device</varname></term> + <listitem><para>An optional device spec that restricts + when the section applies. See <xref linkend="device-spec"/> + for the possible values. + </para></listitem> + </varlistentry> + <varlistentry> + <term><varname>stop-match</varname></term> + <listitem><para>An optional boolean value which defaults to + <literal>no</literal>. If the section matches (based on + <literal>match-device</literal>), further sections will not be + considered even if the property in question is not present. In + the example above, if <literal>[connection-wifi-wlan0]</literal> would + have <literal>stop-match</literal> set to <literal>yes</literal>, + its <literal>ipv6.ip6-privacy</literal> value would be + unspecified. + </para></listitem> + </varlistentry> + </variablelist> + </para> + + <para> + The following properties are supported to have their default values configured: + <variablelist> + <varlistentry> + <term><varname>ipv4.route-metric</varname></term> + </varlistentry> + <varlistentry> + <term><varname>ipv6.ip6-privacy</varname></term> + <listitem><para>If <literal>ipv6.ip6-privacy</literal> is unset, use the content of + "/proc/sys/net/ipv6/conf/default/use_tempaddr" as last fallback. + </para></listitem> + </varlistentry> + <varlistentry> + <term><varname>ipv6.route-metric</varname></term> + </varlistentry> + </variablelist> + </para> + </refsect1> + + <refsect1> <title><literal>connectivity</literal> section</title> <para>This section controls NetworkManager's optional connectivity checking functionality. This allows NetworkManager to detect @@ -607,6 +689,11 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth <listitem><para>Match the device based on the subchannel address. Globbing is not supported</para></listitem> </varlistentry> <varlistentry> + <term>type:TYPE</term> + <listitem><para>Match the device type. Valid type names are as reported by "<literal>nmcli -f GENERAL.TYPE device show</literal>". + Globbing is not supported.</para></listitem> + </varlistentry> + <varlistentry> <term>except:SPEC</term> <listitem><para>Negative match of a device. <literal>SPEC</literal> must be explicitly qualified with a prefix such as <literal>interface-name:</literal>. A negative match has higher priority then the positive diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 980b6a8d96..a989813d47 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -869,6 +869,7 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error #define MAC_TAG "mac:" #define INTERFACE_NAME_TAG "interface-name:" +#define DEVICE_TYPE_TAG "type:" #define SUBCHAN_TAG "s390-subchannels:" #define EXCEPT_TAG "except:" @@ -884,6 +885,37 @@ _match_except (const char *spec_str, gboolean *out_except) } NMMatchSpecMatchType +nm_match_spec_device_type (const GSList *specs, const char *device_type) +{ + const GSList *iter; + NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; + + if (!device_type || !*device_type) + return NM_MATCH_SPEC_NO_MATCH; + + for (iter = specs; iter; iter = g_slist_next (iter)) { + const char *spec_str = iter->data; + gboolean except; + + if (!spec_str || !*spec_str) + continue; + + spec_str = _match_except (spec_str, &except); + + if (g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, STRLEN (DEVICE_TYPE_TAG)) != 0) + continue; + + spec_str += STRLEN (DEVICE_TYPE_TAG); + if (strcmp (spec_str, device_type) == 0) { + if (except) + return NM_MATCH_SPEC_NEG_MATCH; + match = NM_MATCH_SPEC_MATCH; + } + } + return match; +} + +NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr) { const GSList *iter; @@ -901,7 +933,8 @@ nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr) spec_str = _match_except (spec_str, &except); if ( !g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG)) - || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) + || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG)) + || !g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, STRLEN (DEVICE_TYPE_TAG))) continue; if (!g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG))) @@ -937,7 +970,8 @@ nm_match_spec_interface_name (const GSList *specs, const char *interface_name) spec_str = _match_except (spec_str, &except); if ( !g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG)) - || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) + || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG)) + || !g_ascii_strncasecmp (spec_str, DEVICE_TYPE_TAG, STRLEN (DEVICE_TYPE_TAG))) continue; if (!g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG))) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 3bd7252876..03836abd5d 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -102,6 +102,7 @@ typedef enum { NM_MATCH_SPEC_NEG_MATCH = 2, } NMMatchSpecMatchType; +NMMatchSpecMatchType nm_match_spec_device_type (const GSList *specs, const char *device_type); NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name); diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 8b328e07fe..5841d834ff 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -54,6 +54,14 @@ get_generic_capabilities (NMDevice *dev) return NM_DEVICE_CAP_NONE; } +static const char * +get_type_description (NMDevice *device) +{ + if (NM_DEVICE_GENERIC_GET_PRIVATE (device)->type_description) + return NM_DEVICE_GENERIC_GET_PRIVATE (device)->type_description; + return NM_DEVICE_CLASS (nm_device_generic_parent_class)->get_type_description (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -184,6 +192,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; + parent_class->get_type_description = get_type_description; parent_class->check_connection_compatible = check_connection_compatible; parent_class->update_connection = update_connection; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index aab14708bc..3d5cda21b9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -189,6 +189,7 @@ typedef struct { int ip_ifindex; NMDeviceType type; char * type_desc; + char * type_description; NMDeviceCapabilities capabilities; char * driver; char * driver_version; @@ -734,50 +735,63 @@ nm_device_get_priority (NMDevice *self) return 11000; } -guint32 -nm_device_get_ip4_route_metric (NMDevice *self) +static guint32 +_get_ipx_route_metric (NMDevice *self, + gboolean is_v4) { + char *value; + gint64 route_metric; + NMSettingIPConfig *s_ip; NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - gint64 route_metric = -1; g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); connection = nm_device_get_connection (self); - if (connection) - s_ip = nm_connection_get_setting_ip4_config (connection); + if (connection) { + s_ip = is_v4 + ? nm_connection_get_setting_ip4_config (connection) + : nm_connection_get_setting_ip6_config (connection); - /* Slave interfaces don't have IP settings, but we may get here when - * external changes are made or when noticing IP changes when starting - * the slave connection. - */ - if (s_ip) - route_metric = nm_setting_ip_config_get_route_metric (s_ip); + /* Slave interfaces don't have IP settings, but we may get here when + * external changes are made or when noticing IP changes when starting + * the slave connection. + */ + if (s_ip) { + route_metric = nm_setting_ip_config_get_route_metric (s_ip); + if (route_metric >= 0) + goto out; + } + } + + /* use the current NMConfigData, which makes this configuration reloadable. + * Note that that means that the route-metric might change between SIGHUP. + * You must cache the returned value if that is a problem. */ + value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), + is_v4 ? "ipv4.route-metric" : "ipv6.route-metric", self); + if (value) { + route_metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); + g_free (value); - return route_metric >= 0 ? route_metric : nm_device_get_priority (self); + if (route_metric >= 0) + goto out; + } + route_metric = nm_device_get_priority (self); +out: + if (!is_v4) + route_metric = nm_utils_ip6_route_metric_normalize (route_metric); + return route_metric; } guint32 -nm_device_get_ip6_route_metric (NMDevice *self) +nm_device_get_ip4_route_metric (NMDevice *self) { - NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - gint64 route_metric = -1; - - g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); - - connection = nm_device_get_connection (self); - if (connection) - s_ip = nm_connection_get_setting_ip6_config (connection); - - /* Slave interfaces don't have IP settings, but we may get here when - * external changes are made or when noticing IP changes when starting - * the slave connection. - */ - if (s_ip) - route_metric = nm_setting_ip_config_get_route_metric (s_ip); + return _get_ipx_route_metric (self, TRUE); +} - return route_metric >= 0 ? route_metric : nm_device_get_priority (self); +guint32 +nm_device_get_ip6_route_metric (NMDevice *self) +{ + return _get_ipx_route_metric (self, FALSE); } const NMPlatformIP4Route * @@ -818,6 +832,34 @@ nm_device_get_type_desc (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->type_desc; } +const char * +nm_device_get_type_description (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + /* Beware: this function should return the same + * value as nm_device_get_type_description() in libnm. */ + + return NM_DEVICE_GET_CLASS (self)->get_type_description (self); +} + +static const char * +get_type_description (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->type_description) { + const char *typename; + + typename = G_OBJECT_TYPE_NAME (self); + if (g_str_has_prefix (typename, "NMDevice")) + typename += 8; + priv->type_description = g_ascii_strdown (typename, -1); + } + + return priv->type_description; +} + gboolean nm_device_has_carrier (NMDevice *self) { @@ -4555,8 +4597,10 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) } } +/************************************************************************/ + static NMSettingIP6ConfigPrivacy -use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) +_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) { switch (use_tempaddr) { case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: @@ -4568,45 +4612,51 @@ use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) } } -/* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or - * /lib/sysctl.d/sysctl.conf - */ static NMSettingIP6ConfigPrivacy -ip6_use_tempaddr (void) +_ip6_privacy_get (NMDevice *self) { - char *contents = NULL; - const char *group_name = "[forged_group]\n"; - char *sysctl_data = NULL; - GKeyFile *keyfile; - GError *error = NULL; - gint tmp; - NMSettingIP6ConfigPrivacy ret = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + NMSettingIP6ConfigPrivacy ip6_privacy; + gs_free char *value = NULL; + NMConnection *connection; - /* Read file contents to a string. */ - if (!g_file_get_contents ("/etc/sysctl.conf", &contents, NULL, NULL)) - if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, NULL, NULL)) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - /* Prepend a group so that we can use GKeyFile parser. */ - sysctl_data = g_strdup_printf ("%s%s", group_name, contents); + /* 1.) First look at the per-connection setting. If it is not -1 (unknown), + * use it. */ + connection = nm_device_get_connection (self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - keyfile = g_key_file_new (); - if (!g_key_file_load_from_data (keyfile, sysctl_data, -1, G_KEY_FILE_NONE, NULL)) - goto done; + if (s_ip6) { + ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); + ip6_privacy = _ip6_privacy_clamp (ip6_privacy); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + } + } - tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error); - if (error == NULL) - ret = use_tempaddr_clamp (tmp); + value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), + "ipv6.ip6-privacy", self); -done: - g_free (contents); - g_free (sysctl_data); - g_clear_error (&error); - g_key_file_free (keyfile); + /* 2.) use the default value from the configuration. */ + ip6_privacy = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; - return ret; + /* 3.) No valid default-value configured. Fallback to reading sysctl. + * + * Instead of reading static config files in /etc, just read the current sysctl value. + * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves + * the "default" entry untouched. */ + ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/default/use_tempaddr", NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + return _ip6_privacy_clamp (ip6_privacy); } +/****************************************************************/ + static gboolean ip6_requires_slaves (NMConnection *connection) { @@ -4705,18 +4755,7 @@ act_stage3_ip6_config_start (NMDevice *self, /* Re-enable IPv6 on the interface */ set_disable_ipv6 (self, "0"); - /* Enable/disable IPv6 Privacy Extensions. - * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf), - * use that value instead of per-connection value. - */ - ip6_privacy = ip6_use_tempaddr (); - if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) { - NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - - if (s_ip6) - ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); - } - ip6_privacy = use_tempaddr_clamp (ip6_privacy); + ip6_privacy = _ip6_privacy_get (self); if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { if (!addrconf6_start (self, ip6_privacy)) { @@ -8354,6 +8393,10 @@ spec_match_list (NMDevice *self, const GSList *specs) m = nm_match_spec_interface_name (specs, nm_device_get_iface (self)); matched = MAX (matched, m); } + if (matched != NM_MATCH_SPEC_NEG_MATCH) { + m = nm_match_spec_device_type (specs, nm_device_get_type_description (self)); + matched = MAX (matched, m); + } return matched; } @@ -8638,6 +8681,7 @@ finalize (GObject *object) g_free (priv->driver_version); g_free (priv->firmware_version); g_free (priv->type_desc); + g_free (priv->type_description); g_free (priv->dhcp_anycast_address); g_hash_table_unref (priv->ip6_saved_properties); @@ -8655,7 +8699,7 @@ set_property (GObject *object, guint prop_id, NMPlatformLink *platform_device; const char *hw_addr, *p; guint count; - + switch (prop_id) { case PROP_PLATFORM_DEVICE: platform_device = g_value_get_pointer (value); @@ -8917,6 +8961,7 @@ nm_device_class_init (NMDeviceClass *klass) klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; klass->have_any_ready_slaves = have_any_ready_slaves; + klass->get_type_description = get_type_description; klass->spec_match_list = spec_match_list; klass->can_auto_connect = can_auto_connect; klass->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index b44d2c2721..ef61dba72d 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -210,6 +210,8 @@ typedef struct { /* Sync deactivating (in the DISCONNECTED phase) */ void (* deactivate) (NMDevice *self); + const char *(*get_type_description) (NMDevice *self); + NMMatchSpecMatchType (* spec_match_list) (NMDevice *self, const GSList *specs); /* Update the connection with currently configured L2 settings */ @@ -276,6 +278,7 @@ int nm_device_get_ip_ifindex(NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); +const char * nm_device_get_type_description (NMDevice *dev); NMDeviceType nm_device_get_device_type (NMDevice *dev); int nm_device_get_priority (NMDevice *dev); diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index c02f5def9b..ca724c046c 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -372,6 +372,18 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_IS_NON_KERNEL; } +static const char * +get_type_description (NMDevice *device) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + if (NM_FLAGS_HAS (priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)) + return "gsm"; + if (NM_FLAGS_HAS (priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) + return "cdma"; + return NM_DEVICE_CLASS (nm_device_modem_parent_class)->get_type_description (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -741,6 +753,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) object_class->constructed = constructed; device_class->get_generic_capabilities = get_generic_capabilities; + device_class->get_type_description = get_type_description; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 2569f7ca30..e53d8fbb11 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -27,6 +27,19 @@ #include "nm-device.h" #include "gsystem-local-alloc.h" #include "nm-core-internal.h" +#include "nm-utils-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; @@ -163,6 +180,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) { @@ -312,6 +423,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); @@ -327,6 +439,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); @@ -344,6 +464,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 0c3e3d1455..07140f82b6 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -92,6 +92,10 @@ const char *nm_config_data_get_dns_mode (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/nm-config.c b/src/nm-config.c index 25e4902bde..c7e61b559e 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -107,11 +107,11 @@ static void _set_config_data (NMConfig *self, NMConfigData *new_data); /************************************************************************/ -static gboolean -_get_bool_value (GKeyFile *keyfile, - const char *section, - const char *key, - gboolean default_value) +gboolean +nm_config_keyfile_get_boolean (GKeyFile *keyfile, + const char *section, + const char *key, + gboolean default_value) { gboolean value = default_value; char *str; @@ -828,9 +828,9 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) if (!priv->plugins) priv->plugins = g_new0 (char *, 1); - priv->monitor_connection_files = _get_bool_value (keyfile, "main", "monitor-connection-files", FALSE); + priv->monitor_connection_files = nm_config_keyfile_get_boolean (keyfile, "main", "monitor-connection-files", FALSE); - priv->auth_polkit = _get_bool_value (keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT); + priv->auth_polkit = nm_config_keyfile_get_boolean (keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT); priv->dhcp_client = g_key_file_get_value (keyfile, "main", "dhcp", NULL); @@ -839,7 +839,7 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) priv->debug = g_key_file_get_value (keyfile, "main", "debug", NULL); - priv->configure_and_quit = _get_bool_value (keyfile, "main", "configure-and-quit", FALSE); + priv->configure_and_quit = nm_config_keyfile_get_boolean (keyfile, "main", "configure-and-quit", FALSE); no_auto_default_orig_list = nm_config_get_device_match_spec (keyfile, "main", "no-auto-default"); diff --git a/src/nm-config.h b/src/nm-config.h index e72132af9d..29d6566323 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -89,6 +89,10 @@ NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error); void nm_config_reload (NMConfig *config); GKeyFile *nm_config_create_keyfile (void); +gboolean nm_config_keyfile_get_boolean (GKeyFile *keyfile, + const char *section, + const char *key, + gboolean default_value); GSList *nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key); G_END_DECLS diff --git a/src/tests/config/NetworkManager.conf b/src/tests/config/NetworkManager.conf index 401ba48a72..36113661f2 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 67ba5904ec..7ce3c1ee7c 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); } |