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"); } /*****************************************************************************/