mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 02:10:09 +01:00
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 18ecf48d7a)
This commit is contained in:
commit
2f51ba50df
15 changed files with 492 additions and 86 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -439,6 +439,88 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
|
|||
</para>
|
||||
</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
|
||||
|
|
@ -606,6 +688,11 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth
|
|||
<term>s390-subchannels:HWADDR</term>
|
||||
<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
|
||||
|
|
|
|||
|
|
@ -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:"
|
||||
|
||||
|
|
@ -883,6 +884,37 @@ _match_except (const char *spec_str, gboolean *out_except)
|
|||
return spec_str;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -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))) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
return route_metric >= 0 ? route_metric : nm_device_get_priority (self);
|
||||
/* 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);
|
||||
|
||||
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_ip4_route_metric (NMDevice *self)
|
||||
{
|
||||
return _get_ipx_route_metric (self, TRUE);
|
||||
}
|
||||
|
||||
guint32
|
||||
nm_device_get_ip6_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 route_metric >= 0 ? route_metric : nm_device_get_priority (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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue