diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index d3645ee031..98d0c8b19d 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -92,13 +92,14 @@ NmcOutputField nmc_fields_setting_wired[] = {
SETTING_FIELD (NM_SETTING_WIRED_AUTO_NEGOTIATE), /* 4 */
SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS), /* 5 */
SETTING_FIELD (NM_SETTING_WIRED_CLONED_MAC_ADDRESS), /* 6 */
- SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST), /* 7 */
- SETTING_FIELD (NM_SETTING_WIRED_MTU), /* 8 */
- SETTING_FIELD (NM_SETTING_WIRED_S390_SUBCHANNELS), /* 9 */
- SETTING_FIELD (NM_SETTING_WIRED_S390_NETTYPE), /* 10 */
- SETTING_FIELD (NM_SETTING_WIRED_S390_OPTIONS), /* 11 */
- SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN), /* 12 */
- SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD), /* 13 */
+ SETTING_FIELD (NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK), /* 7 */
+ SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST), /* 8 */
+ SETTING_FIELD (NM_SETTING_WIRED_MTU), /* 9 */
+ SETTING_FIELD (NM_SETTING_WIRED_S390_SUBCHANNELS), /* 10 */
+ SETTING_FIELD (NM_SETTING_WIRED_S390_NETTYPE), /* 11 */
+ SETTING_FIELD (NM_SETTING_WIRED_S390_OPTIONS), /* 12 */
+ SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN), /* 13 */
+ SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD), /* 14 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_WIRED_ALL "name"","\
@@ -108,6 +109,7 @@ NmcOutputField nmc_fields_setting_wired[] = {
NM_SETTING_WIRED_AUTO_NEGOTIATE","\
NM_SETTING_WIRED_MAC_ADDRESS","\
NM_SETTING_WIRED_CLONED_MAC_ADDRESS","\
+ NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK","\
NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST","\
NM_SETTING_WIRED_MTU","\
NM_SETTING_WIRED_S390_SUBCHANNELS","\
@@ -203,12 +205,13 @@ NmcOutputField nmc_fields_setting_wireless[] = {
SETTING_FIELD (NM_SETTING_WIRELESS_TX_POWER), /* 7 */
SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS), /* 8 */
SETTING_FIELD (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS), /* 9 */
- SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST), /* 10 */
- SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION), /* 11 */
- SETTING_FIELD (NM_SETTING_WIRELESS_MTU), /* 12 */
- SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS), /* 13 */
- SETTING_FIELD (NM_SETTING_WIRELESS_HIDDEN), /* 14 */
- SETTING_FIELD (NM_SETTING_WIRELESS_POWERSAVE), /* 15 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK), /* 10 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST), /* 11 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION), /* 12 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_MTU), /* 13 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS), /* 14 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_HIDDEN), /* 15 */
+ SETTING_FIELD (NM_SETTING_WIRELESS_POWERSAVE), /* 16 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_WIRELESS_ALL "name"","\
@@ -221,6 +224,7 @@ NmcOutputField nmc_fields_setting_wireless[] = {
NM_SETTING_WIRELESS_TX_POWER","\
NM_SETTING_WIRELESS_MAC_ADDRESS","\
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS","\
+ NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK","\
NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST","\
NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION","\
NM_SETTING_WIRELESS_MTU","\
@@ -1765,6 +1769,7 @@ DEFINE_GETTER (nmc_property_wired_get_duplex, NM_SETTING_WIRED_DUPLEX)
DEFINE_GETTER (nmc_property_wired_get_auto_negotiate, NM_SETTING_WIRED_AUTO_NEGOTIATE)
DEFINE_GETTER (nmc_property_wired_get_mac_address, NM_SETTING_WIRED_MAC_ADDRESS)
DEFINE_GETTER (nmc_property_wired_get_cloned_mac_address, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)
+DEFINE_GETTER (nmc_property_wired_get_generate_mac_address_mask, NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK)
DEFINE_GETTER (nmc_property_wired_get_mac_address_blacklist, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST)
DEFINE_GETTER (nmc_property_wired_get_s390_subchannels, NM_SETTING_WIRED_S390_SUBCHANNELS)
DEFINE_GETTER (nmc_property_wired_get_s390_nettype, NM_SETTING_WIRED_S390_NETTYPE)
@@ -1891,6 +1896,7 @@ DEFINE_GETTER (nmc_property_wireless_get_rate, NM_SETTING_WIRELESS_RATE)
DEFINE_GETTER (nmc_property_wireless_get_tx_power, NM_SETTING_WIRELESS_TX_POWER)
DEFINE_GETTER (nmc_property_wireless_get_mac_address, NM_SETTING_WIRELESS_MAC_ADDRESS)
DEFINE_GETTER (nmc_property_wireless_get_cloned_mac_address, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)
+DEFINE_GETTER (nmc_property_wireless_get_generate_mac_address_mask, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK)
DEFINE_GETTER (nmc_property_wireless_get_mac_address_blacklist, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST)
DEFINE_GETTER (nmc_property_wireless_get_seen_bssids, NM_SETTING_WIRELESS_SEEN_BSSIDS)
DEFINE_GETTER (nmc_property_wireless_get_hidden, NM_SETTING_WIRELESS_HIDDEN)
@@ -7217,6 +7223,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
+ nmc_add_prop_funcs (GLUE (WIRED, GENERATE_MAC_ADDRESS_MASK),
+ nmc_property_wired_get_generate_mac_address_mask,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
nmc_add_prop_funcs (GLUE (WIRED, MAC_ADDRESS_BLACKLIST),
nmc_property_wired_get_mac_address_blacklist,
nmc_property_wired_set_mac_address_blacklist,
@@ -7335,6 +7348,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
+ nmc_add_prop_funcs (GLUE (WIRELESS, GENERATE_MAC_ADDRESS_MASK),
+ nmc_property_wireless_get_generate_mac_address_mask,
+ nmc_property_set_string,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
nmc_add_prop_funcs (GLUE (WIRELESS, MAC_ADDRESS_BLACKLIST),
nmc_property_wireless_get_mac_address_blacklist,
nmc_property_wireless_set_mac_address_blacklist,
@@ -8134,13 +8154,14 @@ setting_wired_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gb
set_val_str (arr, 4, nmc_property_wired_get_auto_negotiate (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 5, nmc_property_wired_get_mac_address (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 6, nmc_property_wired_get_cloned_mac_address (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 7, nmc_property_wired_get_mac_address_blacklist (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 8, nmc_property_wired_get_mtu (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 9, nmc_property_wired_get_s390_subchannels (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 10, nmc_property_wired_get_s390_nettype (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 11, nmc_property_wired_get_s390_options (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 12, nmc_property_wired_get_wake_on_lan (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 13, nmc_property_wired_get_wake_on_lan_password (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 7, nmc_property_wired_get_generate_mac_address_mask (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 8, nmc_property_wired_get_mac_address_blacklist (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 9, nmc_property_wired_get_mtu (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 10, nmc_property_wired_get_s390_subchannels (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 11, nmc_property_wired_get_s390_nettype (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 12, nmc_property_wired_get_s390_options (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 13, nmc_property_wired_get_wake_on_lan (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 14, nmc_property_wired_get_wake_on_lan_password (setting, NMC_PROPERTY_GET_PRETTY));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */
@@ -8234,12 +8255,13 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc, const char *one_prop,
set_val_str (arr, 7, nmc_property_wireless_get_tx_power (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 8, nmc_property_wireless_get_mac_address (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 9, nmc_property_wireless_get_cloned_mac_address (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 10, nmc_property_wireless_get_mac_address_blacklist (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 11, nmc_property_wireless_get_mac_address_randomization (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 12, nmc_property_wireless_get_mtu (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 13, nmc_property_wireless_get_seen_bssids (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 14, nmc_property_wireless_get_hidden (setting, NMC_PROPERTY_GET_PRETTY));
- set_val_str (arr, 15, nmc_property_wireless_get_powersave (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 10, nmc_property_wireless_get_generate_mac_address_mask (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 11, nmc_property_wireless_get_mac_address_blacklist (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 12, nmc_property_wireless_get_mac_address_randomization (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 13, nmc_property_wireless_get_mtu (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 14, nmc_property_wireless_get_seen_bssids (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 15, nmc_property_wireless_get_hidden (setting, NMC_PROPERTY_GET_PRETTY));
+ set_val_str (arr, 16, nmc_property_wireless_get_powersave (setting, NMC_PROPERTY_GET_PRETTY));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 96624d05b8..956c910a87 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -283,6 +283,16 @@ void _nm_setting_vlan_get_priorities (NMSettingVlan *setting,
/***********************************************************/
+struct ether_addr;
+
+gboolean _nm_utils_generate_mac_address_mask_parse (const char *value,
+ struct ether_addr *out_mask,
+ struct ether_addr **out_ouis,
+ gsize *out_ouis_len,
+ GError **error);
+
+/***********************************************************/
+
typedef enum {
NM_BOND_OPTION_TYPE_INT,
NM_BOND_OPTION_TYPE_STRING,
diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c
index 3e72056afd..66ed9c48f0 100644
--- a/libnm-core/nm-setting-wired.c
+++ b/libnm-core/nm-setting-wired.c
@@ -53,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;
@@ -70,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 +190,22 @@ nm_setting_wired_get_cloned_mac_address (NMSettingWired *setting)
return NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address;
}
+/**
+ * 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
@@ -612,6 +630,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
GHashTableIter iter;
const char *key, *value;
int i;
+ GError *local = NULL;
if (priv->port && !g_strv_contains (valid_ports, priv->port)) {
g_set_error (error,
@@ -704,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,
@@ -785,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)
@@ -829,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);
@@ -894,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;
@@ -1121,6 +1162,53 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class)
_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:
*
diff --git a/libnm-core/nm-setting-wired.h b/libnm-core/nm-setting-wired.h
index 6bc6678238..30b0b6c254 100644
--- a/libnm-core/nm-setting-wired.h
+++ b/libnm-core/nm-setting-wired.h
@@ -85,6 +85,7 @@ typedef enum { /*< flags >*/
#define NM_SETTING_WIRED_AUTO_NEGOTIATE "auto-negotiate"
#define NM_SETTING_WIRED_MAC_ADDRESS "mac-address"
#define NM_SETTING_WIRED_CLONED_MAC_ADDRESS "cloned-mac-address"
+#define NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK "generate-mac-address-mask"
#define NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST "mac-address-blacklist"
#define NM_SETTING_WIRED_MTU "mtu"
#define NM_SETTING_WIRED_S390_SUBCHANNELS "s390-subchannels"
@@ -117,6 +118,9 @@ gboolean nm_setting_wired_get_auto_negotiate (NMSettingWired *setting
const char * nm_setting_wired_get_mac_address (NMSettingWired *setting);
const char * nm_setting_wired_get_cloned_mac_address (NMSettingWired *setting);
+NM_AVAILABLE_IN_1_4
+const char * nm_setting_wired_get_generate_mac_address_mask (NMSettingWired *setting);
+
const char * const *nm_setting_wired_get_mac_address_blacklist (NMSettingWired *setting);
guint32 nm_setting_wired_get_num_mac_blacklist_items (NMSettingWired *setting);
const char * nm_setting_wired_get_mac_blacklist_item (NMSettingWired *setting,
diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c
index 15ba71b7f8..2aa29c9ee3 100644
--- a/libnm-core/nm-setting-wireless.c
+++ b/libnm-core/nm-setting-wireless.c
@@ -56,6 +56,7 @@ typedef struct {
guint32 tx_power;
char *device_mac_address;
char *cloned_mac_address;
+ char *generate_mac_address_mask;
GArray *mac_address_blacklist;
guint32 mtu;
GSList *seen_bssids;
@@ -75,6 +76,7 @@ enum {
PROP_TX_POWER,
PROP_MAC_ADDRESS,
PROP_CLONED_MAC_ADDRESS,
+ PROP_GENERATE_MAC_ADDRESS_MASK,
PROP_MAC_ADDRESS_BLACKLIST,
PROP_MTU,
PROP_SEEN_BSSIDS,
@@ -421,6 +423,22 @@ nm_setting_wireless_get_cloned_mac_address (NMSettingWireless *setting)
return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address;
}
+/**
+ * nm_setting_wireless_get_generate_mac_address_mask:
+ * @setting: the #NMSettingWireless
+ *
+ * Returns: the #NMSettingWireless:generate-mac-address-mask property of the setting
+ *
+ * Since: 1.4
+ **/
+const char *
+nm_setting_wireless_get_generate_mac_address_mask (NMSettingWireless *setting)
+{
+ g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NULL);
+
+ return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->generate_mac_address_mask;
+}
+
/**
* nm_setting_wireless_get_mac_address_blacklist:
* @setting: the #NMSettingWireless
@@ -723,6 +741,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
GSList *iter;
int i;
gsize length;
+ GError *local = NULL;
if (!priv->ssid) {
g_set_error_literal (error,
@@ -814,6 +833,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_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK);
+ g_error_free (local);
+ return FALSE;
+ }
+
for (i = 0; i < priv->mac_address_blacklist->len; i++) {
const char *mac = g_array_index (priv->mac_address_blacklist, const char *, i);
@@ -935,6 +968,7 @@ finalize (GObject *object)
g_free (priv->bssid);
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);
g_slist_free_full (priv->seen_bssids, g_free);
@@ -987,6 +1021,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);
@@ -1054,6 +1092,9 @@ get_property (GObject *object, guint prop_id,
case PROP_CLONED_MAC_ADDRESS:
g_value_set_string (value, nm_setting_wireless_get_cloned_mac_address (setting));
break;
+ case PROP_GENERATE_MAC_ADDRESS_MASK:
+ g_value_set_string (value, nm_setting_wireless_get_generate_mac_address_mask (setting));
+ break;
case PROP_MAC_ADDRESS_BLACKLIST:
g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
break;
@@ -1362,6 +1403,53 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_wireless_class)
_nm_utils_hwaddr_cloned_data_synth,
_nm_utils_hwaddr_cloned_data_set);
+ /**
+ * NMSettingWireless:generate-mac-address-mask:
+ *
+ * With #NMSettingWireless: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_WIRELESS_GENERATE_MAC_ADDRESS_MASK, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_FUZZY_IGNORE |
+ G_PARAM_STATIC_STRINGS));
+
/**
* NMSettingWireless:mac-address-blacklist:
*
diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h
index 574cee54f2..35fa79c179 100644
--- a/libnm-core/nm-setting-wireless.h
+++ b/libnm-core/nm-setting-wireless.h
@@ -50,6 +50,7 @@ G_BEGIN_DECLS
#define NM_SETTING_WIRELESS_TX_POWER "tx-power"
#define NM_SETTING_WIRELESS_MAC_ADDRESS "mac-address"
#define NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS "cloned-mac-address"
+#define NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK "generate-mac-address-mask"
#define NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST "mac-address-blacklist"
#define NM_SETTING_WIRELESS_MTU "mtu"
#define NM_SETTING_WIRELESS_SEEN_BSSIDS "seen-bssids"
@@ -126,6 +127,9 @@ guint32 nm_setting_wireless_get_tx_power (NMSettingWireless
const char *nm_setting_wireless_get_mac_address (NMSettingWireless *setting);
const char *nm_setting_wireless_get_cloned_mac_address (NMSettingWireless *setting);
+NM_AVAILABLE_IN_1_4
+const char *nm_setting_wireless_get_generate_mac_address_mask (NMSettingWireless *setting);
+
const char * const *nm_setting_wireless_get_mac_address_blacklist (NMSettingWireless *setting);
guint32 nm_setting_wireless_get_num_mac_blacklist_items (NMSettingWireless *setting);
const char * nm_setting_wireless_get_mac_blacklist_item (NMSettingWireless *setting,
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 7567f6d88d..50575b30c9 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -3446,6 +3446,91 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
/*****************************************************************************/
+static char *
+_split_word (char *s)
+{
+ /* takes @s and truncates the string on the first white-space.
+ * then it returns the first word afterwards (again seeking
+ * over leading white-space). */
+ for (; s[0]; s++) {
+ if (g_ascii_isspace (s[0])) {
+ s[0] = '\0';
+ s++;
+ while (g_ascii_isspace (s[0]))
+ s++;
+ return s;
+ }
+ }
+ return s;
+}
+
+gboolean
+_nm_utils_generate_mac_address_mask_parse (const char *value,
+ struct ether_addr *out_mask,
+ struct ether_addr **out_ouis,
+ gsize *out_ouis_len,
+ GError **error)
+{
+ gs_free char *s_free = NULL;
+ char *s, *s_next;
+ struct ether_addr mask;
+ gs_unref_array GArray *ouis = NULL;
+
+ g_return_val_if_fail (!error || !*error, FALSE);
+
+ if (!value || !*value) {
+ /* NULL and "" are valid values and both mean the default
+ * "q */
+ if (out_mask) {
+ memset (out_mask, 0, sizeof (*out_mask));
+ out_mask->ether_addr_octet[0] |= 0x02;
+ }
+ NM_SET_OUT (out_ouis, NULL);
+ NM_SET_OUT (out_ouis_len, 0);
+ return TRUE;
+ }
+
+ s_free = g_strdup (value);
+ s = s_free;
+
+ /* skip over leading whitespace */
+ while (g_ascii_isspace (s[0]))
+ s++;
+
+ /* parse the first mask */
+ s_next = _split_word (s);
+ if (!nm_utils_hwaddr_aton (s, &mask, ETH_ALEN)) {
+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ _("not a valid ethernet MAC address for mask at position %lld"),
+ (long long) (s - s_free));
+ return FALSE;
+ }
+
+ if (s_next[0]) {
+ ouis = g_array_sized_new (FALSE, FALSE, sizeof (struct ether_addr), 4);
+
+ do {
+ s = s_next;
+ s_next = _split_word (s);
+
+ g_array_set_size (ouis, ouis->len + 1);
+ if (!nm_utils_hwaddr_aton (s, &g_array_index (ouis, struct ether_addr, ouis->len - 1), ETH_ALEN)) {
+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ _("not a valid ethernet MAC address #%u at position %lld"),
+ ouis->len, (long long) (s - s_free));
+ return FALSE;
+ }
+ } while (s_next[0]);
+ }
+
+ NM_SET_OUT (out_mask, mask);
+ NM_SET_OUT (out_ouis_len, ouis ? ouis->len : 0);
+ NM_SET_OUT (out_ouis, ouis ? ((struct ether_addr *) g_array_free (g_steal_pointer (&ouis), FALSE)) : NULL);
+ return TRUE;
+}
+
+/*****************************************************************************/
+
/**
* nm_utils_bin2hexstr:
* @src: (type guint8) (array length=len): an array of bytes
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 6e4be2cffc..aef9f2b13d 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -1941,6 +1941,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_WIRED_AUTO_NEGOTIATE, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_MAC_ADDRESS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_CLONED_MAC_ADDRESS, NM_SETTING_DIFF_RESULT_IN_A },
+ { NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_MTU, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_S390_SUBCHANNELS, NM_SETTING_DIFF_RESULT_IN_A },
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 47f6598ff6..cc2fc7df62 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1069,6 +1069,8 @@ global:
nm_setting_connection_get_stable_id;
nm_setting_ip6_config_get_token;
nm_setting_ip_config_get_dns_priority;
+ nm_setting_wired_get_generate_mac_address_mask;
+ nm_setting_wireless_get_generate_mac_address_mask;
nm_vpn_editor_plugin_get_plugin_info;
nm_vpn_editor_plugin_get_vt;
nm_vpn_editor_plugin_load;
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 344aa9585c..220a12c6a7 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -569,6 +569,9 @@ ipv6.ip6-privacy=0
ethernet.cloned-mac-address
If left unspecified, it defaults to "permanent".
+
+ ethernet.generate-mac-address-mask
+
ethernet.wake-on-lan
@@ -600,6 +603,9 @@ ipv6.ip6-privacy=0
wifi.cloned-mac-address
If left unspecified, it defaults to "permanent".
+
+ wifi.generate-mac-address-mask
+
wifi.mac-address-randomization
If left unspecified, MAC address randomization is disabled.
@@ -751,6 +757,17 @@ unmanaged=1
+
+ wifi.scan-generate-mac-address-mask
+
+
+ Like the per-connection settings ethernet.generate-mac-address-mask
+ and wifi.generate-mac-address-mask, this allows to configure the
+ generated MAC addresses during scanning. See manual of nm-settings
+ for details.
+
+
+
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d1b0e56357..4bd8c25ad6 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -11589,6 +11589,34 @@ _get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gbool
return addr;
}
+static const char *
+_get_generate_mac_address_mask_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_value)
+{
+ NMSetting *setting;
+ const char *value = NULL;
+ char *a;
+
+ nm_assert (out_value && !*out_value);
+
+ setting = nm_connection_get_setting (connection,
+ is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED);
+ if (setting) {
+ value = is_wifi
+ ? nm_setting_wireless_get_generate_mac_address_mask ((NMSettingWireless *) setting)
+ : nm_setting_wired_get_generate_mac_address_mask ((NMSettingWired *) setting);
+ if (value)
+ return value;
+ }
+
+ a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+ is_wifi ? "wifi.generate-mac-address-mask" : "ethernet.generate-mac-mac-address-mask",
+ self);
+ if (!a)
+ return NULL;
+ *out_value = a;
+ return a;
+}
+
gboolean
nm_device_hw_addr_is_explict (NMDevice *self)
{
@@ -11695,6 +11723,7 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean
NMDevicePrivate *priv;
gs_free char *hw_addr_tmp = NULL;
gs_free char *hw_addr_generated = NULL;
+ gs_free char *generate_mac_address_mask_tmp = NULL;
const char *addr, *addr_setting;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
@@ -11717,7 +11746,8 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean
return FALSE;
priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT;
} else if (NM_IN_STRSET (addr, NM_CLONED_MAC_RANDOM)) {
- hw_addr_generated = nm_utils_hw_addr_gen_random_eth ();
+ hw_addr_generated = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (self),
+ _get_generate_mac_address_mask_setting (self, connection, is_wifi, &generate_mac_address_mask_tmp));
if (!hw_addr_generated) {
_LOGW (LOGD_DEVICE, "set-hw-addr: failed to generate %s MAC address", "random");
return FALSE;
@@ -11731,7 +11761,9 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean
stable_id = _get_stable_id (connection, &stable_type);
if (stable_id) {
hw_addr_generated = nm_utils_hw_addr_gen_stable_eth (stable_type, stable_id,
- nm_device_get_ip_iface (self));
+ nm_device_get_ip_iface (self),
+ nm_device_get_initial_hw_address (self),
+ _get_generate_mac_address_mask_setting (self, connection, is_wifi, &generate_mac_address_mask_tmp));
}
if (!hw_addr_generated) {
_LOGW (LOGD_DEVICE, "set-hw-addr: failed to generate %s MAC address", "stable");
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 3db69cd890..5ddf5d84b7 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -1064,6 +1064,8 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset)
if ( !priv->hw_addr_scan
|| now >= priv->hw_addr_scan_expire) {
+ gs_free char *generate_mac_address_mask = NULL;
+
/* the random MAC address for scanning expires after a while.
*
* We don't bother with to update the MAC address exactly when
@@ -1071,8 +1073,14 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset)
* a new one.*/
priv->hw_addr_scan_expire = now + (SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN * 60);
+ generate_mac_address_mask = nm_config_data_get_device_config (NM_CONFIG_GET_DATA,
+ "wifi.scan-generate-mac-address-mask",
+ device,
+ NULL);
+
g_free (priv->hw_addr_scan);
- priv->hw_addr_scan = nm_utils_hw_addr_gen_random_eth ();
+ priv->hw_addr_scan = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (device),
+ generate_mac_address_mask);
}
nm_device_hw_addr_set (device, priv->hw_addr_scan, "scanning");
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 06989fa710..6dfbb4ce10 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -3176,27 +3176,68 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type,
/*****************************************************************************/
static void
-_hw_addr_eth_complete (guint8 *bin_addr)
+_hw_addr_eth_complete (struct ether_addr *addr,
+ const char *current_mac_address,
+ const char *generate_mac_address_mask)
{
- /* this LSB of the first octet cannot be set,
- * it means Unicast vs. Multicast */
- bin_addr[0] &= ~1;
+ struct ether_addr mask;
+ struct ether_addr oui;
+ struct ether_addr *ouis;
+ gsize ouis_len;
+ guint i;
/* the second LSB of the first octet means
* "globally unique, OUI enforced, BIA (burned-in-address)"
- * vs. "locally-administered" */
- bin_addr[0] |= 2;
+ * vs. "locally-administered". By default, set it to
+ * generate locally-administered addresses.
+ *
+ * Maybe be overwritten by a mask below. */
+ addr->ether_addr_octet[0] |= 2;
+
+ if (!generate_mac_address_mask || !*generate_mac_address_mask)
+ goto out;
+ if (!_nm_utils_generate_mac_address_mask_parse (generate_mac_address_mask,
+ &mask,
+ &ouis,
+ &ouis_len,
+ NULL))
+ goto out;
+
+ nm_assert ((ouis == NULL) ^ (ouis_len != 0));
+ if (ouis) {
+ /* g_random_int() is good enough here. It uses a static GRand instance
+ * that is seeded from /dev/urandom. */
+ oui = ouis[g_random_int () % ouis_len];
+ g_free (ouis);
+ } else {
+ if (!nm_utils_hwaddr_aton (current_mac_address, &oui, ETH_ALEN))
+ goto out;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ const guint8 a = addr->ether_addr_octet[i];
+ const guint8 o = oui.ether_addr_octet[i];
+ const guint8 m = mask.ether_addr_octet[i];
+
+ addr->ether_addr_octet[i] = (a & ~m) | (o & m);
+ }
+
+out:
+ /* The LSB of the first octet must always be cleared,
+ * it means Unicast vs. Multicast */
+ addr->ether_addr_octet[0] &= ~1;
}
char *
-nm_utils_hw_addr_gen_random_eth (void)
+nm_utils_hw_addr_gen_random_eth (const char *current_mac_address,
+ const char *generate_mac_address_mask)
{
- guint8 bin_addr[ETH_ALEN];
+ struct ether_addr bin_addr;
- if (nm_utils_read_urandom (bin_addr, ETH_ALEN) < 0)
+ if (nm_utils_read_urandom (&bin_addr, ETH_ALEN) < 0)
return NULL;
- _hw_addr_eth_complete (bin_addr);
- return nm_utils_hwaddr_ntoa (bin_addr, ETH_ALEN);
+ _hw_addr_eth_complete (&bin_addr, current_mac_address, generate_mac_address_mask);
+ return nm_utils_hwaddr_ntoa (&bin_addr, ETH_ALEN);
}
static char *
@@ -3204,13 +3245,15 @@ _hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
const guint8 *secret_key,
gsize key_len,
- const char *ifname)
+ const char *ifname,
+ const char *current_mac_address,
+ const char *generate_mac_address_mask)
{
GChecksum *sum;
guint32 tmp;
guint8 digest[32];
gsize len = sizeof (digest);
- guint8 bin_addr[ETH_ALEN];
+ struct ether_addr bin_addr;
guint8 stable_type_uint8;
nm_assert (stable_id);
@@ -3239,15 +3282,17 @@ _hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
g_return_val_if_fail (len == 32, NULL);
- memcpy (bin_addr, digest, ETH_ALEN);
- _hw_addr_eth_complete (bin_addr);
- return nm_utils_hwaddr_ntoa (bin_addr, ETH_ALEN);
+ memcpy (&bin_addr, digest, ETH_ALEN);
+ _hw_addr_eth_complete (&bin_addr, current_mac_address, generate_mac_address_mask);
+ return nm_utils_hwaddr_ntoa (&bin_addr, ETH_ALEN);
}
char *
nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
- const char *ifname)
+ const char *ifname,
+ const char *current_mac_address,
+ const char *generate_mac_address_mask)
{
gs_free guint8 *secret_key = NULL;
gsize key_len = 0;
@@ -3262,7 +3307,9 @@ nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
stable_id,
secret_key,
key_len,
- ifname);
+ ifname,
+ current_mac_address,
+ generate_mac_address_mask);
}
/*****************************************************************************/
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index 082eabf4f6..bfba35f575 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -371,10 +371,13 @@ gboolean nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType id_type,
guint dad_counter,
GError **error);
-char *nm_utils_hw_addr_gen_random_eth (void);
+char *nm_utils_hw_addr_gen_random_eth (const char *current_mac_address,
+ const char *generate_mac_address_mask);
char *nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
- const char *iname);
+ const char *ifname,
+ const char *current_mac_address,
+ const char *generate_mac_address_mask);
void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 192327043b..af5d291026 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -3368,6 +3368,10 @@ make_wireless_setting (shvarFile *ifcfg,
g_free (value);
}
+ value = svGetValue (ifcfg, "GENERATE_MAC_ADDRESS_MASK", FALSE);
+ g_object_set (s_wireless, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, value, NULL);
+ g_free (value);
+
value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
if (value) {
char **strv;
@@ -3882,6 +3886,10 @@ make_wired_setting (shvarFile *ifcfg,
g_free (value);
}
+ value = svGetValue (ifcfg, "GENERATE_MAC_ADDRESS_MASK", FALSE);
+ g_object_set (s_wired, NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK, value, NULL);
+ g_free (value);
+
value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
if (value) {
char **strv;
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index 1683a0e33c..3682640077 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -853,6 +853,10 @@ write_wireless_setting (NMConnection *connection,
cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
svSetValue (ifcfg, "MACADDR", cloned_mac, FALSE);
+ svSetValue (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
+ nm_setting_wireless_get_generate_mac_address_mask (s_wireless),
+ FALSE);
+
svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE);
macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
if (macaddr_blacklist[0]) {
@@ -1111,6 +1115,10 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
svSetValue (ifcfg, "MACADDR", cloned_mac, FALSE);
+ svSetValue (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
+ nm_setting_wired_get_generate_mac_address_mask (s_wired),
+ FALSE);
+
svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE);
macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
if (macaddr_blacklist[0]) {
@@ -1260,6 +1268,10 @@ write_wired_for_virtual (NMConnection *connection, shvarFile *ifcfg)
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
svSetValue (ifcfg, "MACADDR", cloned_mac, FALSE);
+ svSetValue (ifcfg, "GENERATE_MAC_ADDRESS_MASK",
+ nm_setting_wired_get_generate_mac_address_mask (s_wired),
+ FALSE);
+
mtu = nm_setting_wired_get_mtu (s_wired);
if (mtu) {
tmp = g_strdup_printf ("%u", mtu);
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
index 2a3fd9d63d..000a9d1ef4 100644
--- a/src/tests/test-utils.c
+++ b/src/tests/test-utils.c
@@ -64,32 +64,60 @@ _do_test_hw_addr (NMUtilsStableType stable_type,
const guint8 *secret_key,
gsize key_len,
const char *ifname,
- const char *expected)
+ const char *current_mac_address,
+ const char *generate_mac_address_mask,
+ const char **expected)
{
gs_free char *generated = NULL;
+ const char **e;
+ gboolean found = FALSE;
- g_assert (expected);
- g_assert (nm_utils_hwaddr_valid (expected, ETH_ALEN));
+ for (e = expected; *e; e++) {
+ g_assert (*e);
+ g_assert (nm_utils_hwaddr_valid (*e, ETH_ALEN));
+ }
generated = _hw_addr_gen_stable_eth (stable_type,
stable_id,
secret_key,
key_len,
- ifname);
+ ifname,
+ current_mac_address,
+ generate_mac_address_mask);
g_assert (generated);
g_assert (nm_utils_hwaddr_valid (generated, ETH_ALEN));
- g_assert_cmpstr (generated, ==, expected);
- g_assert (nm_utils_hwaddr_matches (generated, -1, expected, -1));
+ for (e = expected; *e; e++) {
+ if (!nm_utils_hwaddr_matches (generated, -1, *e, -1))
+ continue;
+ g_assert (!found);
+ found = TRUE;
+ g_assert_cmpstr (generated, ==, *e);
+ }
+ g_assert (found);
}
-#define do_test_hw_addr(stable_type, stable_id, secret_key, ifname, expected) \
- _do_test_hw_addr ((stable_type), (stable_id), (const guint8 *) ""secret_key"", NM_STRLEN (secret_key), (ifname), ""expected"")
+#define do_test_hw_addr(stable_type, stable_id, secret_key, ifname, current_mac_address, generate_mac_address_mask, ...) \
+ _do_test_hw_addr ((stable_type), (stable_id), (const guint8 *) ""secret_key"", NM_STRLEN (secret_key), (ifname), ""current_mac_address"", generate_mac_address_mask, (const char *[]) { __VA_ARGS__, NULL })
static void
test_hw_addr_gen_stable_eth (void)
{
- do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "06:0D:CD:0C:9E:2C");
- do_test_hw_addr (NM_UTILS_STABLE_TYPE_STABLE_ID, "stable-1", "key1", "eth0", "C6:AE:A9:9A:76:09");
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", NULL, "06:0D:CD:0C:9E:2C");
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_STABLE_ID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", NULL, "C6:AE:A9:9A:76:09");
+
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "FF:FF:FF:00:00:00", "00:23:45:0C:9E:2C");
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "03:23:45:67:89:ab", "FF:FF:FF:00:00:00", "02:23:45:0C:9E:2C");
+
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "00:00:00:00:00:00", "06:0D:CD:0C:9E:2C");
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "02:00:00:00:00:00", "04:0D:CD:0C:9E:2C");
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "02:00:00:00:00:00", "04:0D:CD:0C:9E:2C");
+
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "02:00:00:00:00:00 00:00:00:00:00:00", "04:0D:CD:0C:9E:2C");
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "02:00:00:00:00:00 02:00:00:00:00:00", "06:0D:CD:0C:9E:2C");
+
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "00:00:00:00:00:00 E9:60:CE:F5:ED:2F", "06:0D:CD:0C:9E:2C");
+
+ do_test_hw_addr (NM_UTILS_STABLE_TYPE_UUID, "stable-1", "key1", "eth0", "01:23:45:67:89:ab", "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00", "06:0D:CD:0C:9E:2C", "04:0D:CD:0C:9E:2C");
}
/*****************************************************************************/