summary refs log tree commit diff
path: root/libnm-core/nm-setting-wired.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core/nm-setting-wired.c')
-rw-r--r--libnm-core/nm-setting-wired.c183
1 files changed, 166 insertions, 17 deletions
diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c
index 132f8e05..fc5ab3e5 100644
--- a/libnm-core/nm-setting-wired.c
+++ b/libnm-core/nm-setting-wired.c
@@ -28,6 +28,7 @@
 #include <net/ethernet.h>
 
 #include "nm-utils.h"
+#include "nm-common-macros.h"
 #include "nm-utils-private.h"
 #include "nm-setting-private.h"
 
@@ -52,6 +53,7 @@ typedef struct {
 	gboolean auto_negotiate;
 	char *device_mac_address;
 	char *cloned_mac_address;
+	char *generate_mac_address_mask;
 	GArray *mac_address_blacklist;
 	guint32 mtu;
 	char **s390_subchannels;
@@ -69,6 +71,7 @@ enum {
 	PROP_AUTO_NEGOTIATE,
 	PROP_MAC_ADDRESS,
 	PROP_CLONED_MAC_ADDRESS,
+	PROP_GENERATE_MAC_ADDRESS_MASK,
 	PROP_MAC_ADDRESS_BLACKLIST,
 	PROP_MTU,
 	PROP_S390_SUBCHANNELS,
@@ -188,6 +191,22 @@ nm_setting_wired_get_cloned_mac_address (NMSettingWired *setting)
 }
 
 /**
+ * nm_setting_wired_get_generate_mac_address_mask:
+ * @setting: the #NMSettingWired
+ *
+ * Returns: the #NMSettingWired:generate-mac-address-mask property of the setting
+ *
+ * Since: 1.4
+ **/
+const char *
+nm_setting_wired_get_generate_mac_address_mask (NMSettingWired *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL);
+
+	return NM_SETTING_WIRED_GET_PRIVATE (setting)->generate_mac_address_mask;
+}
+
+/**
  * nm_setting_wired_get_mac_address_blacklist:
  * @setting: the #NMSettingWired
  *
@@ -504,7 +523,7 @@ nm_setting_wired_add_s390_option (NMSettingWired *setting,
 	g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE);
 	g_return_val_if_fail (key != NULL, FALSE);
 	g_return_val_if_fail (strlen (key), FALSE);
-	g_return_val_if_fail (_nm_utils_string_in_list (key, valid_s390_opts), FALSE);
+	g_return_val_if_fail (g_strv_contains (valid_s390_opts, key), FALSE);
 	g_return_val_if_fail (value != NULL, FALSE);
 
 	value_len = strlen (value);
@@ -611,8 +630,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	GHashTableIter iter;
 	const char *key, *value;
 	int i;
+	GError *local = NULL;
 
-	if (priv->port && !_nm_utils_string_in_list (priv->port, valid_ports)) {
+	if (priv->port && !g_strv_contains (valid_ports, priv->port)) {
 		g_set_error (error,
 		             NM_CONNECTION_ERROR,
 		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -622,7 +642,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		return FALSE;
 	}
 
-	if (priv->duplex && !_nm_utils_string_in_list (priv->duplex, valid_duplex)) {
+	if (priv->duplex && !g_strv_contains (valid_duplex, priv->duplex)) {
 		g_set_error (error,
 		             NM_CONNECTION_ERROR,
 		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -668,7 +688,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		}
 	}
 
-	if (priv->s390_nettype && !_nm_utils_string_in_list (priv->s390_nettype, valid_nettype)) {
+	if (priv->s390_nettype && !g_strv_contains (valid_nettype, priv->s390_nettype)) {
 		g_set_error_literal (error,
 		                     NM_CONNECTION_ERROR,
 		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -679,7 +699,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 
 	g_hash_table_iter_init (&iter, priv->s390_options);
 	while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) {
-		if (   !_nm_utils_string_in_list (key, valid_s390_opts)
+		if (   !g_strv_contains (valid_s390_opts, key)
 		    || !strlen (value)
 		    || (strlen (value) > 200)) {
 			g_set_error (error,
@@ -692,7 +712,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		}
 	}
 
-	if (priv->cloned_mac_address && !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) {
+	if (   priv->cloned_mac_address
+	    && !NM_CLONED_MAC_IS_SPECIAL (priv->cloned_mac_address)
+	    && !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) {
 		g_set_error_literal (error,
 		                     NM_CONNECTION_ERROR,
 		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -701,6 +723,20 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		return FALSE;
 	}
 
+	/* generate-mac-address-mask only makes sense with cloned-mac-address "random" or
+	 * "stable". Still, let's not be so strict about that and accept the value
+	 * even if it is unused. */
+	if (!_nm_utils_generate_mac_address_mask_parse (priv->generate_mac_address_mask,
+	                                                NULL, NULL, NULL, &local)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     local->message);
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK);
+		g_error_free (local);
+		return FALSE;
+	}
+
 	if (   NM_FLAGS_ANY (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS)
 	    && !nm_utils_is_power_of_two (priv->wol)) {
 		g_set_error_literal (error,
@@ -732,6 +768,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 	return TRUE;
 }
 
+static gboolean
+compare_property (NMSetting *setting,
+                  NMSetting *other,
+                  const GParamSpec *prop_spec,
+                  NMSettingCompareFlags flags)
+{
+	NMSettingClass *parent_class;
+
+	if (nm_streq (prop_spec->name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) {
+		return nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address,
+		                  NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address);
+	}
+
+	parent_class = NM_SETTING_CLASS (nm_setting_wired_parent_class);
+	return parent_class->compare_property (setting, other, prop_spec, flags);
+}
+
+/*****************************************************************************/
+
 static void
 clear_blacklist_item (char **item_p)
 {
@@ -763,6 +818,7 @@ finalize (GObject *object)
 
 	g_free (priv->device_mac_address);
 	g_free (priv->cloned_mac_address);
+	g_free (priv->generate_mac_address_mask);
 	g_array_unref (priv->mac_address_blacklist);
 
 	if (priv->s390_subchannels)
@@ -807,6 +863,10 @@ set_property (GObject *object, guint prop_id,
 		priv->cloned_mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
 		                                                                  ETH_ALEN);
 		break;
+	case PROP_GENERATE_MAC_ADDRESS_MASK:
+		g_free (priv->generate_mac_address_mask);
+		priv->generate_mac_address_mask = g_value_dup_string (value);
+		break;
 	case PROP_MAC_ADDRESS_BLACKLIST:
 		blacklist = g_value_get_boxed (value);
 		g_array_set_size (priv->mac_address_blacklist, 0);
@@ -872,6 +932,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_CLONED_MAC_ADDRESS:
 		g_value_set_string (value, nm_setting_wired_get_cloned_mac_address (setting));
 		break;
+	case PROP_GENERATE_MAC_ADDRESS_MASK:
+		g_value_set_string (value, nm_setting_wired_get_generate_mac_address_mask (setting));
+		break;
 	case PROP_MAC_ADDRESS_BLACKLIST:
 		g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
 		break;
@@ -900,18 +963,19 @@ get_property (GObject *object, guint prop_id,
 }
 
 static void
-nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
+nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
-	NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
+	GObjectClass *object_class = G_OBJECT_CLASS (setting_wired_class);
+	NMSettingClass *setting_class = NM_SETTING_CLASS (setting_wired_class);
 
-	g_type_class_add_private (setting_class, sizeof (NMSettingWiredPrivate));
+	g_type_class_add_private (setting_wired_class, sizeof (NMSettingWiredPrivate));
 
 	/* virtual methods */
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
 	object_class->finalize     = finalize;
-	parent_class->verify       = verify;
+	setting_class->verify      = verify;
+	setting_class->compare_property = compare_property;
 
 	/* Properties */
 	/**
@@ -1023,7 +1087,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
 		                      G_PARAM_READWRITE |
 		                      NM_SETTING_PARAM_INFERRABLE |
 		                      G_PARAM_STATIC_STRINGS));
-	_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_MAC_ADDRESS,
+	_nm_setting_class_transform_property (setting_class, NM_SETTING_WIRED_MAC_ADDRESS,
 	                                      G_VARIANT_TYPE_BYTESTRING,
 	                                      _nm_utils_hwaddr_to_dbus,
 	                                      _nm_utils_hwaddr_from_dbus);
@@ -1033,6 +1097,20 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
 	 *
 	 * If specified, request that the device use this MAC address instead of its
 	 * permanent MAC address.  This is known as MAC cloning or spoofing.
+	 *
+	 * Beside explicitly specifing a MAC address, the special values "preserve", "permanent",
+	 * "random" and "stable" are supported.
+	 * "preserve" means not to touch the MAC address on activation.
+	 * "permanent" means to use the permanent hardware address of the device.
+	 * "random" creates a random MAC address on each connect.
+	 * "stable" creates a hashed MAC address based on connection.stable-id (or
+	 * the connection's UUID) and a machine dependent key.
+	 *
+	 * If unspecified, the value can be overwritten via global defaults, see manual
+	 * of NetworkManager.conf. If still unspecified, it defaults to "permanent".
+	 *
+	 * On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated
+	 * "cloned-mac-address".
 	 **/
 	/* ---keyfile---
 	 * property: cloned-mac-address
@@ -1047,6 +1125,12 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
 	 * description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons
 	 *    notation (e.g. 00:22:68:14:5A:99).
 	 * ---end---
+	 * ---dbus---
+	 * property: cloned-mac-address
+	 * format: byte array
+	 * description: This D-Bus field is deprecated in favor of "assigned-mac-address"
+	 *    which is more flexible and allows specifying special variants like "random".
+	 * ---end---
 	 */
 	g_object_class_install_property
 		(object_class, PROP_CLONED_MAC_ADDRESS,
@@ -1055,10 +1139,75 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
 		                      G_PARAM_READWRITE |
 		                      NM_SETTING_PARAM_INFERRABLE |
 		                      G_PARAM_STATIC_STRINGS));
-	_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
-	                                      G_VARIANT_TYPE_BYTESTRING,
-	                                      _nm_utils_hwaddr_to_dbus,
-	                                      _nm_utils_hwaddr_from_dbus);
+	_nm_setting_class_override_property (setting_class,
+	                                     NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
+	                                     G_VARIANT_TYPE_BYTESTRING,
+	                                     _nm_utils_hwaddr_cloned_get,
+	                                     _nm_utils_hwaddr_cloned_set,
+	                                     _nm_utils_hwaddr_cloned_not_set);
+
+	/* ---dbus---
+	 * property: assigned-mac-address
+	 * format: string
+	 * description: The new field for the cloned MAC address. It can be either
+	 *   a hardware address in ASCII representation, or one of the special values
+	 *   "preserve", "permanent", "random" or "stable".
+	 *   This field replaces the deprecated "cloned-mac-address" on D-Bus, which
+	 *   can only contain explict hardware addresses.
+	 * ---end---
+	 */
+	_nm_setting_class_add_dbus_only_property (setting_class,
+	                                          "assigned-mac-address",
+	                                          G_VARIANT_TYPE_STRING,
+	                                          _nm_utils_hwaddr_cloned_data_synth,
+	                                          _nm_utils_hwaddr_cloned_data_set);
+
+	/**
+	 * NMSettingWired:generate-mac-address-mask:
+	 *
+	 * With #NMSettingWired:cloned-mac-address setting "random" or "stable",
+	 * by default all bits of the MAC address are scrambled and a locally-administered,
+	 * unicast MAC address is created. This property allows to specify that certain bits
+	 * are fixed. Note that the least significant bit of the first MAC address will
+	 * always be unset to create a unicast MAC address.
+	 *
+	 * If the property is %NULL, it is eligible to be overwritten by a default
+	 * connection setting. If the value is still %NULL or an empty string, the
+	 * default is to create a locally-administered, unicast MAC address.
+	 *
+	 * If the value contains one MAC address, this address is used as mask. The set
+	 * bits of the mask are to be filled with the current MAC address of the device,
+	 * while the unset bits are subject to randomization.
+	 * Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address
+	 * and only randomize the lower 3 bytes using the "random" or "stable" algorithm.
+	 *
+	 * If the value contains one additional MAC address after the mask,
+	 * this address is used instead of the current MAC address to fill the bits
+	 * that shall not be randomized. For example, a value of
+	 * "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address
+	 * to 68:F7:28, while the lower bits are randomized. A value of
+	 * "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled
+	 * globally-administered, burned-in MAC address.
+	 *
+	 * If the value contains more then one additional MAC addresses, one of
+	 * them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00"
+	 * will create a fully scrambled MAC address, randomly locally or globally
+	 * administered.
+	 **/
+	/* ---ifcfg-rh---
+	 * property: generate-mac-address-mask
+	 * variable: GENERATE_MAC_ADDRESS_MASK
+	 * description: the MAC address mask for generating randomized and stable
+	 *   cloned-mac-address.
+	 * ---end---
+	 */
+	g_object_class_install_property
+	    (object_class, PROP_GENERATE_MAC_ADDRESS_MASK,
+	     g_param_spec_string (NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, "", "",
+	                          NULL,
+	                          G_PARAM_READWRITE |
+	                          NM_SETTING_PARAM_FUZZY_IGNORE |
+	                          G_PARAM_STATIC_STRINGS));
 
 	/**
 	 * NMSettingWired:mac-address-blacklist:
@@ -1183,7 +1332,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
 		                     G_PARAM_READWRITE |
 		                     NM_SETTING_PARAM_INFERRABLE |
 		                     G_PARAM_STATIC_STRINGS));
-	_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_S390_OPTIONS,
+	_nm_setting_class_transform_property (setting_class, NM_SETTING_WIRED_S390_OPTIONS,
 	                                      G_VARIANT_TYPE ("a{ss}"),
 	                                      _nm_utils_strdict_to_dbus,
 	                                      _nm_utils_strdict_from_dbus);