Thomas Haller 2016-06-30 08:36:58 +02:00
commit 9a354cdc90
61 changed files with 2770 additions and 755 deletions

View file

@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "nm-common-macros.h"
#include "utils.h" #include "utils.h"
#include "common.h" #include "common.h"
#include "nm-vpn-helpers.h" #include "nm-vpn-helpers.h"
@ -44,26 +45,28 @@ NmcOutputField nmc_fields_setting_connection[] = {
SETTING_FIELD ("name"), /* 0 */ SETTING_FIELD ("name"), /* 0 */
SETTING_FIELD (NM_SETTING_CONNECTION_ID), /* 1 */ SETTING_FIELD (NM_SETTING_CONNECTION_ID), /* 1 */
SETTING_FIELD (NM_SETTING_CONNECTION_UUID), /* 2 */ SETTING_FIELD (NM_SETTING_CONNECTION_UUID), /* 2 */
SETTING_FIELD (NM_SETTING_CONNECTION_INTERFACE_NAME), /* 3 */ SETTING_FIELD (NM_SETTING_CONNECTION_STABLE_ID), /* 3 */
SETTING_FIELD (NM_SETTING_CONNECTION_TYPE), /* 4 */ SETTING_FIELD (NM_SETTING_CONNECTION_INTERFACE_NAME), /* 4 */
SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT), /* 5 */ SETTING_FIELD (NM_SETTING_CONNECTION_TYPE), /* 5 */
SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY), /* 6 */ SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT), /* 6 */
SETTING_FIELD (NM_SETTING_CONNECTION_TIMESTAMP), /* 7 */ SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY), /* 7 */
SETTING_FIELD (NM_SETTING_CONNECTION_READ_ONLY), /* 8 */ SETTING_FIELD (NM_SETTING_CONNECTION_TIMESTAMP), /* 8 */
SETTING_FIELD (NM_SETTING_CONNECTION_PERMISSIONS), /* 9 */ SETTING_FIELD (NM_SETTING_CONNECTION_READ_ONLY), /* 9 */
SETTING_FIELD (NM_SETTING_CONNECTION_ZONE), /* 10 */ SETTING_FIELD (NM_SETTING_CONNECTION_PERMISSIONS), /* 10 */
SETTING_FIELD (NM_SETTING_CONNECTION_MASTER), /* 11 */ SETTING_FIELD (NM_SETTING_CONNECTION_ZONE), /* 11 */
SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE), /* 12 */ SETTING_FIELD (NM_SETTING_CONNECTION_MASTER), /* 12 */
SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES), /* 13 */ SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE), /* 13 */
SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES), /* 14 */ SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES), /* 14 */
SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT), /* 15 */ SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES), /* 15 */
SETTING_FIELD (NM_SETTING_CONNECTION_METERED), /* 16 */ SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT), /* 16 */
SETTING_FIELD (NM_SETTING_CONNECTION_LLDP), /* 17 */ SETTING_FIELD (NM_SETTING_CONNECTION_METERED), /* 17 */
SETTING_FIELD (NM_SETTING_CONNECTION_LLDP), /* 18 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0} {NULL, NULL, 0, NULL, FALSE, FALSE, 0}
}; };
#define NMC_FIELDS_SETTING_CONNECTION_ALL "name"","\ #define NMC_FIELDS_SETTING_CONNECTION_ALL "name"","\
NM_SETTING_CONNECTION_ID","\ NM_SETTING_CONNECTION_ID","\
NM_SETTING_CONNECTION_UUID","\ NM_SETTING_CONNECTION_UUID","\
NM_SETTING_CONNECTION_STABLE_ID","\
NM_SETTING_CONNECTION_INTERFACE_NAME","\ NM_SETTING_CONNECTION_INTERFACE_NAME","\
NM_SETTING_CONNECTION_TYPE","\ NM_SETTING_CONNECTION_TYPE","\
NM_SETTING_CONNECTION_AUTOCONNECT","\ NM_SETTING_CONNECTION_AUTOCONNECT","\
@ -89,13 +92,14 @@ NmcOutputField nmc_fields_setting_wired[] = {
SETTING_FIELD (NM_SETTING_WIRED_AUTO_NEGOTIATE), /* 4 */ SETTING_FIELD (NM_SETTING_WIRED_AUTO_NEGOTIATE), /* 4 */
SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS), /* 5 */ SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS), /* 5 */
SETTING_FIELD (NM_SETTING_WIRED_CLONED_MAC_ADDRESS), /* 6 */ SETTING_FIELD (NM_SETTING_WIRED_CLONED_MAC_ADDRESS), /* 6 */
SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST), /* 7 */ SETTING_FIELD (NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK), /* 7 */
SETTING_FIELD (NM_SETTING_WIRED_MTU), /* 8 */ SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST), /* 8 */
SETTING_FIELD (NM_SETTING_WIRED_S390_SUBCHANNELS), /* 9 */ SETTING_FIELD (NM_SETTING_WIRED_MTU), /* 9 */
SETTING_FIELD (NM_SETTING_WIRED_S390_NETTYPE), /* 10 */ SETTING_FIELD (NM_SETTING_WIRED_S390_SUBCHANNELS), /* 10 */
SETTING_FIELD (NM_SETTING_WIRED_S390_OPTIONS), /* 11 */ SETTING_FIELD (NM_SETTING_WIRED_S390_NETTYPE), /* 11 */
SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN), /* 12 */ SETTING_FIELD (NM_SETTING_WIRED_S390_OPTIONS), /* 12 */
SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD), /* 13 */ 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} {NULL, NULL, 0, NULL, FALSE, FALSE, 0}
}; };
#define NMC_FIELDS_SETTING_WIRED_ALL "name"","\ #define NMC_FIELDS_SETTING_WIRED_ALL "name"","\
@ -105,6 +109,7 @@ NmcOutputField nmc_fields_setting_wired[] = {
NM_SETTING_WIRED_AUTO_NEGOTIATE","\ NM_SETTING_WIRED_AUTO_NEGOTIATE","\
NM_SETTING_WIRED_MAC_ADDRESS","\ NM_SETTING_WIRED_MAC_ADDRESS","\
NM_SETTING_WIRED_CLONED_MAC_ADDRESS","\ NM_SETTING_WIRED_CLONED_MAC_ADDRESS","\
NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK","\
NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST","\ NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST","\
NM_SETTING_WIRED_MTU","\ NM_SETTING_WIRED_MTU","\
NM_SETTING_WIRED_S390_SUBCHANNELS","\ NM_SETTING_WIRED_S390_SUBCHANNELS","\
@ -200,12 +205,13 @@ NmcOutputField nmc_fields_setting_wireless[] = {
SETTING_FIELD (NM_SETTING_WIRELESS_TX_POWER), /* 7 */ SETTING_FIELD (NM_SETTING_WIRELESS_TX_POWER), /* 7 */
SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS), /* 8 */ SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS), /* 8 */
SETTING_FIELD (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS), /* 9 */ SETTING_FIELD (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS), /* 9 */
SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST), /* 10 */ SETTING_FIELD (NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK), /* 10 */
SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION), /* 11 */ SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST), /* 11 */
SETTING_FIELD (NM_SETTING_WIRELESS_MTU), /* 12 */ SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION), /* 12 */
SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS), /* 13 */ SETTING_FIELD (NM_SETTING_WIRELESS_MTU), /* 13 */
SETTING_FIELD (NM_SETTING_WIRELESS_HIDDEN), /* 14 */ SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS), /* 14 */
SETTING_FIELD (NM_SETTING_WIRELESS_POWERSAVE), /* 15 */ SETTING_FIELD (NM_SETTING_WIRELESS_HIDDEN), /* 15 */
SETTING_FIELD (NM_SETTING_WIRELESS_POWERSAVE), /* 16 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0} {NULL, NULL, 0, NULL, FALSE, FALSE, 0}
}; };
#define NMC_FIELDS_SETTING_WIRELESS_ALL "name"","\ #define NMC_FIELDS_SETTING_WIRELESS_ALL "name"","\
@ -218,6 +224,7 @@ NmcOutputField nmc_fields_setting_wireless[] = {
NM_SETTING_WIRELESS_TX_POWER","\ NM_SETTING_WIRELESS_TX_POWER","\
NM_SETTING_WIRELESS_MAC_ADDRESS","\ NM_SETTING_WIRELESS_MAC_ADDRESS","\
NM_SETTING_WIRELESS_CLONED_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_BLACKLIST","\
NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION","\ NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION","\
NM_SETTING_WIRELESS_MTU","\ NM_SETTING_WIRELESS_MTU","\
@ -1252,6 +1259,7 @@ DEFINE_SECRET_FLAGS_GETTER (nmc_property_cdma_get_password_flags, NM_SETTING_CDM
/* --- NM_SETTING_CONNECTION_SETTING_NAME property get functions --- */ /* --- NM_SETTING_CONNECTION_SETTING_NAME property get functions --- */
DEFINE_GETTER (nmc_property_connection_get_id, NM_SETTING_CONNECTION_ID) DEFINE_GETTER (nmc_property_connection_get_id, NM_SETTING_CONNECTION_ID)
DEFINE_GETTER (nmc_property_connection_get_uuid, NM_SETTING_CONNECTION_UUID) DEFINE_GETTER (nmc_property_connection_get_uuid, NM_SETTING_CONNECTION_UUID)
DEFINE_GETTER (nmc_property_connection_get_stable_id, NM_SETTING_CONNECTION_STABLE_ID)
DEFINE_GETTER (nmc_property_connection_get_interface_name, NM_SETTING_CONNECTION_INTERFACE_NAME) DEFINE_GETTER (nmc_property_connection_get_interface_name, NM_SETTING_CONNECTION_INTERFACE_NAME)
DEFINE_GETTER (nmc_property_connection_get_type, NM_SETTING_CONNECTION_TYPE) DEFINE_GETTER (nmc_property_connection_get_type, NM_SETTING_CONNECTION_TYPE)
DEFINE_GETTER (nmc_property_connection_get_autoconnect, NM_SETTING_CONNECTION_AUTOCONNECT) DEFINE_GETTER (nmc_property_connection_get_autoconnect, NM_SETTING_CONNECTION_AUTOCONNECT)
@ -1761,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_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_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_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_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_subchannels, NM_SETTING_WIRED_S390_SUBCHANNELS)
DEFINE_GETTER (nmc_property_wired_get_s390_nettype, NM_SETTING_WIRED_S390_NETTYPE) DEFINE_GETTER (nmc_property_wired_get_s390_nettype, NM_SETTING_WIRED_S390_NETTYPE)
@ -1887,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_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_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_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_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_seen_bssids, NM_SETTING_WIRELESS_SEEN_BSSIDS)
DEFINE_GETTER (nmc_property_wireless_get_hidden, NM_SETTING_WIRELESS_HIDDEN) DEFINE_GETTER (nmc_property_wireless_get_hidden, NM_SETTING_WIRELESS_HIDDEN)
@ -2886,11 +2896,12 @@ nmc_property_set_ssid (NMSetting *setting, const char *prop, const char *val, GE
} }
static gboolean static gboolean
nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GError **error) _property_set_mac (NMSetting *setting, const char *prop, const char *val, gboolean cloned_mac_addr, GError **error)
{ {
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (!nm_utils_hwaddr_valid (val, ETH_ALEN)) { if ( (!cloned_mac_addr || !NM_CLONED_MAC_IS_SPECIAL (val))
&& !nm_utils_hwaddr_valid (val, ETH_ALEN)) {
g_set_error (error, 1, 0, _("'%s' is not a valid Ethernet MAC"), val); g_set_error (error, 1, 0, _("'%s' is not a valid Ethernet MAC"), val);
return FALSE; return FALSE;
} }
@ -2899,6 +2910,18 @@ nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GEr
return TRUE; return TRUE;
} }
static gboolean
nmc_property_set_mac (NMSetting *setting, const char *prop, const char *val, GError **error)
{
return _property_set_mac (setting, prop, val, FALSE, error);
}
static gboolean
nmc_property_set_mac_cloned (NMSetting *setting, const char *prop, const char *val, GError **error)
{
return _property_set_mac (setting, prop, val, TRUE, error);
}
static gboolean static gboolean
nmc_property_set_mtu (NMSetting *setting, const char *prop, const char *val, GError **error) nmc_property_set_mtu (NMSetting *setting, const char *prop, const char *val, GError **error)
{ {
@ -6217,6 +6240,13 @@ nmc_properties_init (void)
NULL, NULL,
NULL, NULL,
NULL); NULL);
nmc_add_prop_funcs (GLUE (CONNECTION, STABLE_ID),
nmc_property_connection_get_stable_id,
nmc_property_set_string,
NULL,
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (CONNECTION, INTERFACE_NAME), nmc_add_prop_funcs (GLUE (CONNECTION, INTERFACE_NAME),
nmc_property_connection_get_interface_name, nmc_property_connection_get_interface_name,
nmc_property_set_ifname, nmc_property_set_ifname,
@ -7188,7 +7218,14 @@ nmc_properties_init (void)
NULL); NULL);
nmc_add_prop_funcs (GLUE (WIRED, CLONED_MAC_ADDRESS), nmc_add_prop_funcs (GLUE (WIRED, CLONED_MAC_ADDRESS),
nmc_property_wired_get_cloned_mac_address, nmc_property_wired_get_cloned_mac_address,
nmc_property_set_mac, nmc_property_set_mac_cloned,
NULL,
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,
NULL, NULL,
@ -7306,7 +7343,14 @@ nmc_properties_init (void)
NULL); NULL);
nmc_add_prop_funcs (GLUE (WIRELESS, CLONED_MAC_ADDRESS), nmc_add_prop_funcs (GLUE (WIRELESS, CLONED_MAC_ADDRESS),
nmc_property_wireless_get_cloned_mac_address, nmc_property_wireless_get_cloned_mac_address,
nmc_property_set_mac, nmc_property_set_mac_cloned,
NULL,
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,
NULL, NULL,
@ -8063,21 +8107,22 @@ setting_connection_details (NMSetting *setting, NmCli *nmc, const char *one_pro
set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting))); set_val_str (arr, 0, g_strdup (nm_setting_get_name (setting)));
set_val_str (arr, 1, nmc_property_connection_get_id (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 1, nmc_property_connection_get_id (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 2, nmc_property_connection_get_uuid (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 2, nmc_property_connection_get_uuid (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 3, nmc_property_connection_get_interface_name (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 3, nmc_property_connection_get_stable_id (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 4, nmc_property_connection_get_type (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 4, nmc_property_connection_get_interface_name (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 5, nmc_property_connection_get_autoconnect (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 5, nmc_property_connection_get_type (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 6, nmc_property_connection_get_autoconnect_priority (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 6, nmc_property_connection_get_autoconnect (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 7, nmc_property_connection_get_timestamp (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 7, nmc_property_connection_get_autoconnect_priority (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 8, nmc_property_connection_get_read_only (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 8, nmc_property_connection_get_timestamp (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 9, nmc_property_connection_get_permissions (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 9, nmc_property_connection_get_read_only (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 10, nmc_property_connection_get_zone (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 10, nmc_property_connection_get_permissions (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 11, nmc_property_connection_get_master (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 11, nmc_property_connection_get_zone (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 12, nmc_property_connection_get_slave_type (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 12, nmc_property_connection_get_master (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 13, nmc_property_connection_get_autoconnect_slaves (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 13, nmc_property_connection_get_slave_type (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 14, nmc_property_connection_get_secondaries (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 14, nmc_property_connection_get_autoconnect_slaves (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 15, nmc_property_connection_get_gateway_ping_timeout (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 15, nmc_property_connection_get_secondaries (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 16, nmc_property_connection_get_metered (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 16, nmc_property_connection_get_gateway_ping_timeout (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 17, nmc_property_connection_get_lldp (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 17, nmc_property_connection_get_metered (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 18, nmc_property_connection_get_lldp (setting, NMC_PROPERTY_GET_PRETTY));
g_ptr_array_add (nmc->output_data, arr); g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */ print_data (nmc); /* Print all data */
@ -8109,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, 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, 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, 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, 7, nmc_property_wired_get_generate_mac_address_mask (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 8, nmc_property_wired_get_mtu (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_s390_subchannels (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_nettype (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_options (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_wake_on_lan (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_password (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); g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */ print_data (nmc); /* Print all data */
@ -8209,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, 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, 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, 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, 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_randomization (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_mtu (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_seen_bssids (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_hidden (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_powersave (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); g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */ print_data (nmc); /* Print all data */

View file

@ -28,11 +28,13 @@
#include "nm-default.h" #include "nm-default.h"
#include "nmt-mac-entry.h"
#include <string.h> #include <string.h>
#include "NetworkManager.h" #include "NetworkManager.h"
#include "nm-common-macros.h"
#include "nmt-mac-entry.h"
G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY) G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY)
@ -41,6 +43,7 @@ G_DEFINE_TYPE (NmtMacEntry, nmt_mac_entry, NMT_TYPE_NEWT_ENTRY)
typedef struct { typedef struct {
int mac_length; int mac_length;
int mac_str_length; int mac_str_length;
NmtMacEntryType entry_type;
} NmtMacEntryPrivate; } NmtMacEntryPrivate;
@ -48,6 +51,7 @@ enum {
PROP_0, PROP_0,
PROP_MAC_LENGTH, PROP_MAC_LENGTH,
PROP_MAC_ADDRESS, PROP_MAC_ADDRESS,
PROP_ENTRY_TYPE,
LAST_PROP LAST_PROP
}; };
@ -57,6 +61,7 @@ enum {
* @width: the width in characters of the entry * @width: the width in characters of the entry
* @mac_length: the length in bytes of the hardware address * @mac_length: the length in bytes of the hardware address
* (either %ETH_ALEN or %INFINIBAND_ALEN) * (either %ETH_ALEN or %INFINIBAND_ALEN)
* @entry_type: the type of the entry.
* *
* Creates a new #NmtMacEntry. * Creates a new #NmtMacEntry.
* *
@ -64,11 +69,13 @@ enum {
*/ */
NmtNewtWidget * NmtNewtWidget *
nmt_mac_entry_new (int width, nmt_mac_entry_new (int width,
int mac_length) int mac_length,
NmtMacEntryType entry_type)
{ {
return g_object_new (NMT_TYPE_MAC_ENTRY, return g_object_new (NMT_TYPE_MAC_ENTRY,
"width", width, "width", width,
"mac-length", mac_length, "mac-length", mac_length,
"entry-type", (int) entry_type,
NULL); NULL);
} }
@ -81,6 +88,9 @@ mac_filter (NmtNewtEntry *entry,
{ {
NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (entry); NmtMacEntryPrivate *priv = NMT_MAC_ENTRY_GET_PRIVATE (entry);
if (priv->entry_type != NMT_MAC_ENTRY_TYPE_MAC)
return TRUE;
if (position >= priv->mac_str_length) if (position >= priv->mac_str_length)
return FALSE; return FALSE;
@ -98,6 +108,11 @@ mac_validator (NmtNewtEntry *entry,
if (!*text) if (!*text)
return TRUE; return TRUE;
if (priv->entry_type == NMT_MAC_ENTRY_TYPE_CLONED) {
if (NM_CLONED_MAC_IS_SPECIAL (text))
return TRUE;
}
p = text; p = text;
while ( g_ascii_isxdigit (p[0]) while ( g_ascii_isxdigit (p[0])
&& g_ascii_isxdigit (p[1]) && g_ascii_isxdigit (p[1])
@ -112,7 +127,9 @@ mac_validator (NmtNewtEntry *entry,
if (!*p) if (!*p)
return (p - text == priv->mac_str_length); return (p - text == priv->mac_str_length);
if (g_ascii_isxdigit (p[0]) && !p[1]) { if ( g_ascii_isxdigit (p[0])
&& !p[1]
&& p - text < priv->mac_str_length) {
char *fixed = g_strdup_printf ("%.*s:%c", (int)(p - text), text, *p); char *fixed = g_strdup_printf ("%.*s:%c", (int)(p - text), text, *p);
nmt_newt_entry_set_text (entry, fixed); nmt_newt_entry_set_text (entry, fixed);
@ -161,6 +178,10 @@ nmt_mac_entry_set_property (GObject *object,
case PROP_MAC_ADDRESS: case PROP_MAC_ADDRESS:
nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), g_value_get_string (value)); nmt_newt_entry_set_text (NMT_NEWT_ENTRY (object), g_value_get_string (value));
break; break;
case PROP_ENTRY_TYPE:
/* construct-only */
priv->entry_type = g_value_get_int (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -182,6 +203,9 @@ nmt_mac_entry_get_property (GObject *object,
case PROP_MAC_ADDRESS: case PROP_MAC_ADDRESS:
g_value_set_string (value, nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object))); g_value_set_string (value, nmt_newt_entry_get_text (NMT_NEWT_ENTRY (object)));
break; break;
case PROP_ENTRY_TYPE:
g_value_set_int (value, priv->entry_type);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -224,4 +248,17 @@ nmt_mac_entry_class_init (NmtMacEntryClass *entry_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
/**
* NmtMacEntry:entry-type:
*
* The type of the #NmtMacEntry. Can be either used for plain
* MAC addresses or for the extended format for cloned MAC addresses.
*/
g_object_class_install_property
(object_class, PROP_ENTRY_TYPE,
g_param_spec_int ("entry-type", "", "",
NMT_MAC_ENTRY_TYPE_MAC, NMT_MAC_ENTRY_TYPE_CLONED, NMT_MAC_ENTRY_TYPE_MAC,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
} }

View file

@ -25,6 +25,11 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum { /*< skip >*/
NMT_MAC_ENTRY_TYPE_MAC,
NMT_MAC_ENTRY_TYPE_CLONED,
} NmtMacEntryType;
#define NMT_TYPE_MAC_ENTRY (nmt_mac_entry_get_type ()) #define NMT_TYPE_MAC_ENTRY (nmt_mac_entry_get_type ())
#define NMT_MAC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_MAC_ENTRY, NmtMacEntry)) #define NMT_MAC_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMT_TYPE_MAC_ENTRY, NmtMacEntry))
#define NMT_MAC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_MAC_ENTRY, NmtMacEntryClass)) #define NMT_MAC_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMT_TYPE_MAC_ENTRY, NmtMacEntryClass))
@ -45,7 +50,8 @@ typedef struct {
GType nmt_mac_entry_get_type (void); GType nmt_mac_entry_get_type (void);
NmtNewtWidget *nmt_mac_entry_new (int width, NmtNewtWidget *nmt_mac_entry_new (int width,
int mac_length); int mac_length,
NmtMacEntryType type);
G_END_DECLS G_END_DECLS

View file

@ -70,7 +70,7 @@ nmt_page_ethernet_constructed (GObject *object)
section = nmt_editor_section_new (_("ETHERNET"), NULL, FALSE); section = nmt_editor_section_new (_("ETHERNET"), NULL, FALSE);
grid = nmt_editor_section_get_body (section); grid = nmt_editor_section_get_body (section);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

View file

@ -115,7 +115,7 @@ nmt_page_vlan_constructed (GObject *object)
nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, g_object_bind_property (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

View file

@ -351,13 +351,13 @@ nmt_page_wifi_constructed (GObject *object)
nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL); nmt_editor_grid_append (grid, NULL, nmt_newt_separator_new (), NULL);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_MAC);
g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_BSSID, g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_BSSID,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
nmt_editor_grid_append (grid, _("BSSID"), widget, NULL); nmt_editor_grid_append (grid, _("BSSID"), widget, NULL);
widget = nmt_mac_entry_new (40, ETH_ALEN); widget = nmt_mac_entry_new (40, ETH_ALEN, NMT_MAC_ENTRY_TYPE_CLONED);
g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, g_object_bind_property (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
widget, "mac-address", widget, "mac-address",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

View file

@ -847,6 +847,52 @@ _normalize_bond_mode (NMConnection *self, GHashTable *parameters)
return FALSE; return FALSE;
} }
static gboolean
_normalize_wireless_mac_address_randomization (NMConnection *self, GHashTable *parameters)
{
NMSettingWireless *s_wifi = nm_connection_get_setting_wireless (self);
const char *cloned_mac_address;
NMSettingMacRandomization mac_address_randomization;
if (!s_wifi)
return FALSE;
mac_address_randomization = nm_setting_wireless_get_mac_address_randomization (s_wifi);
if (!NM_IN_SET (mac_address_randomization,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
NM_SETTING_MAC_RANDOMIZATION_NEVER,
NM_SETTING_MAC_RANDOMIZATION_ALWAYS))
return FALSE;
cloned_mac_address = nm_setting_wireless_get_cloned_mac_address (s_wifi);
if (cloned_mac_address) {
if (nm_streq (cloned_mac_address, "random")) {
if (mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_ALWAYS)
return FALSE;
mac_address_randomization = NM_SETTING_MAC_RANDOMIZATION_ALWAYS;
} else if (nm_streq (cloned_mac_address, "permanent")) {
if (mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_NEVER)
return FALSE;
mac_address_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER;
} else {
if (mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT)
return FALSE;
mac_address_randomization = NM_SETTING_MAC_RANDOMIZATION_DEFAULT;
}
g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, mac_address_randomization, NULL);
return TRUE;
}
if (mac_address_randomization != NM_SETTING_MAC_RANDOMIZATION_DEFAULT) {
g_object_set (s_wifi,
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_ALWAYS
? "random" : "permanent",
NULL);
return TRUE;
}
return FALSE;
}
/** /**
* nm_connection_verify: * nm_connection_verify:
* @connection: the #NMConnection to verify * @connection: the #NMConnection to verify
@ -1089,6 +1135,7 @@ nm_connection_normalize (NMConnection *connection,
was_modified |= _normalize_ip_config (connection, parameters); was_modified |= _normalize_ip_config (connection, parameters);
was_modified |= _normalize_infiniband_mtu (connection, parameters); was_modified |= _normalize_infiniband_mtu (connection, parameters);
was_modified |= _normalize_bond_mode (connection, parameters); was_modified |= _normalize_bond_mode (connection, parameters);
was_modified |= _normalize_wireless_mac_address_randomization (connection, parameters);
/* Verify anew. */ /* Verify anew. */
success = _nm_connection_verify (connection, error); success = _nm_connection_verify (connection, error);

View file

@ -124,6 +124,8 @@ guint32 _nm_setting_get_setting_priority (NMSetting *setting);
gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value); gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
guint _nm_utils_hwaddr_length (const char *asc);
GSList * _nm_utils_hash_values_to_slist (GHashTable *hash); GSList * _nm_utils_hash_values_to_slist (GHashTable *hash);
GHashTable *_nm_utils_copy_strdict (GHashTable *strdict); GHashTable *_nm_utils_copy_strdict (GHashTable *strdict);
@ -281,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 { typedef enum {
NM_BOND_OPTION_TYPE_INT, NM_BOND_OPTION_TYPE_INT,
NM_BOND_OPTION_TYPE_STRING, NM_BOND_OPTION_TYPE_STRING,

View file

@ -31,6 +31,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <string.h> #include <string.h>
#include "nm-common-macros.h"
#include "nm-core-internal.h" #include "nm-core-internal.h"
#include "nm-keyfile-utils.h" #include "nm-keyfile-utils.h"
@ -581,19 +582,28 @@ ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const cha
} }
static void static void
mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length) mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length, gboolean cloned_mac_addr)
{ {
const char *setting_name = nm_setting_get_name (setting); const char *setting_name = nm_setting_get_name (setting);
char *tmp_string = NULL, *p, *mac_str; gs_free char *tmp_string = NULL;
gint *tmp_list; const char *p, *mac_str;
GByteArray *array = NULL; gs_free guint8 *buf_arr = NULL;
guint buf_len;
gsize length; gsize length;
p = tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL); tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
if ( cloned_mac_addr
&& NM_CLONED_MAC_IS_SPECIAL (tmp_string)) {
mac_str = tmp_string;
goto out;
}
if (tmp_string && tmp_string[0]) { if (tmp_string && tmp_string[0]) {
/* Look for enough ':' characters to signify a MAC address */ /* Look for enough ':' characters to signify a MAC address */
guint i = 0; guint i = 0;
p = tmp_string;
while (*p) { while (*p) {
if (*p == ':') if (*p == ':')
i++; i++;
@ -602,23 +612,24 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
if (enforce_length == 0 || enforce_length == i+1) { if (enforce_length == 0 || enforce_length == i+1) {
/* If we found enough it's probably a string-format MAC address */ /* If we found enough it's probably a string-format MAC address */
array = g_byte_array_sized_new (i+1); buf_len = i + 1;
g_byte_array_set_size (array, i+1); buf_arr = g_new (guint8, buf_len);
if (!nm_utils_hwaddr_aton (tmp_string, array->data, array->len)) { if (!nm_utils_hwaddr_aton (tmp_string, buf_arr, buf_len))
g_byte_array_unref (array); g_clear_pointer (&buf_arr, g_free);
array = NULL;
} }
} }
} g_clear_pointer (&tmp_string, g_free);
g_free (tmp_string);
if (!buf_arr) {
gs_free int *tmp_list = NULL;
if (array == NULL) {
/* Old format; list of ints */ /* Old format; list of ints */
tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL); tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
if (length > 0 && (enforce_length == 0 || enforce_length == length)) { if (length > 0 && (enforce_length == 0 || enforce_length == length)) {
gsize i; gsize i;
array = g_byte_array_sized_new (length); buf_len = length;
buf_arr = g_new (guint8, buf_len);
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
int val = tmp_list[i]; int val = tmp_list[i];
const guint8 v = (guint8) (val & 0xFF); const guint8 v = (guint8) (val & 0xFF);
@ -627,38 +638,42 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN, handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"), _("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
val); val);
g_byte_array_free (array, TRUE);
g_free (tmp_list);
return; return;
} }
g_byte_array_append (array, &v, 1); buf_arr[i] = v;
} }
} }
g_free (tmp_list);
} }
if (!array) { if (!buf_arr) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN, handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid MAC address")); _("ignoring invalid MAC address"));
return; return;
} }
mac_str = nm_utils_hwaddr_ntoa (array->data, array->len); tmp_string = nm_utils_hwaddr_ntoa (buf_arr, buf_len);
mac_str = tmp_string;
out:
g_object_set (setting, key, mac_str, NULL); g_object_set (setting, key, mac_str, NULL);
g_free (mac_str);
g_byte_array_free (array, TRUE);
} }
static void static void
mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key) mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{ {
mac_address_parser (info, setting, key, ETH_ALEN); mac_address_parser (info, setting, key, ETH_ALEN, FALSE);
}
static void
mac_address_parser_ETHER_cloned (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
mac_address_parser (info, setting, key, ETH_ALEN, TRUE);
} }
static void static void
mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key) mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{ {
mac_address_parser (info, setting, key, INFINIBAND_ALEN); mac_address_parser (info, setting, key, INFINIBAND_ALEN, FALSE);
} }
static void static void
@ -1209,7 +1224,7 @@ static KeyParser key_parsers[] = {
{ NM_SETTING_WIRED_SETTING_NAME, { NM_SETTING_WIRED_SETTING_NAME,
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
TRUE, TRUE,
mac_address_parser_ETHER }, mac_address_parser_ETHER_cloned },
{ NM_SETTING_WIRELESS_SETTING_NAME, { NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_MAC_ADDRESS, NM_SETTING_WIRELESS_MAC_ADDRESS,
TRUE, TRUE,
@ -1217,7 +1232,7 @@ static KeyParser key_parsers[] = {
{ NM_SETTING_WIRELESS_SETTING_NAME, { NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
TRUE, TRUE,
mac_address_parser_ETHER }, mac_address_parser_ETHER_cloned },
{ NM_SETTING_WIRELESS_SETTING_NAME, { NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_BSSID, NM_SETTING_WIRELESS_BSSID,
TRUE, TRUE,

View file

@ -63,6 +63,7 @@ typedef struct {
typedef struct { typedef struct {
char *id; char *id;
char *uuid; char *uuid;
char *stable_id;
char *interface_name; char *interface_name;
char *type; char *type;
char *master; char *master;
@ -99,6 +100,7 @@ enum {
PROP_GATEWAY_PING_TIMEOUT, PROP_GATEWAY_PING_TIMEOUT,
PROP_METERED, PROP_METERED,
PROP_LLDP, PROP_LLDP,
PROP_STABLE_ID,
LAST_PROP LAST_PROP
}; };
@ -230,6 +232,24 @@ nm_setting_connection_get_uuid (NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->uuid; return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->uuid;
} }
/**
* nm_setting_connection_get_stable_id:
* @setting: the #NMSettingConnection
*
* Returns the #NMSettingConnection:stable_id property of the connection.
*
* Returns: the stable-id for the connection
*
* Since: 1.4
**/
const char *
nm_setting_connection_get_stable_id (NMSettingConnection *setting)
{
g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), NULL);
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->stable_id;
}
/** /**
* nm_setting_connection_get_interface_name: * nm_setting_connection_get_interface_name:
* @setting: the #NMSettingConnection * @setting: the #NMSettingConnection
@ -1128,6 +1148,7 @@ finalize (GObject *object)
g_free (priv->id); g_free (priv->id);
g_free (priv->uuid); g_free (priv->uuid);
g_free (priv->stable_id);
g_free (priv->interface_name); g_free (priv->interface_name);
g_free (priv->type); g_free (priv->type);
g_free (priv->zone); g_free (priv->zone);
@ -1174,6 +1195,10 @@ set_property (GObject *object, guint prop_id,
g_free (priv->uuid); g_free (priv->uuid);
priv->uuid = g_value_dup_string (value); priv->uuid = g_value_dup_string (value);
break; break;
case PROP_STABLE_ID:
g_free (priv->stable_id);
priv->stable_id = g_value_dup_string (value);
break;
case PROP_INTERFACE_NAME: case PROP_INTERFACE_NAME:
g_free (priv->interface_name); g_free (priv->interface_name);
priv->interface_name = g_value_dup_string (value); priv->interface_name = g_value_dup_string (value);
@ -1260,6 +1285,9 @@ get_property (GObject *object, guint prop_id,
case PROP_UUID: case PROP_UUID:
g_value_set_string (value, nm_setting_connection_get_uuid (setting)); g_value_set_string (value, nm_setting_connection_get_uuid (setting));
break; break;
case PROP_STABLE_ID:
g_value_set_string (value, nm_setting_connection_get_stable_id (setting));
break;
case PROP_INTERFACE_NAME: case PROP_INTERFACE_NAME:
g_value_set_string (value, nm_setting_connection_get_interface_name (setting)); g_value_set_string (value, nm_setting_connection_get_interface_name (setting));
break; break;
@ -1368,7 +1396,7 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
* property: uuid * property: uuid
* variable: UUID(+) * variable: UUID(+)
* description: UUID for the connection profile. When missing, NetworkManager * description: UUID for the connection profile. When missing, NetworkManager
* creates the UUID itself (by hashing the file). * creates the UUID itself (by hashing the filename).
* ---end--- * ---end---
*/ */
g_object_class_install_property g_object_class_install_property
@ -1379,6 +1407,33 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
/**
* NMSettingConnection:stable-id:
*
* This token to generate stable IDs for the connection. If unset,
* the UUID will be used instead.
*
* The stable-id is used instead of the connection UUID for generating
* IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy.
* It is also used to seed the generated cloned MAC address for
* ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable.
*
* Since: 1.4
**/
/* ---ifcfg-rh---
* property: stable-id
* variable: STABLE_ID(+)
* description: Token to generate stable IDs.
* ---end---
*/
g_object_class_install_property
(object_class, PROP_STABLE_ID,
g_param_spec_string (NM_SETTING_CONNECTION_STABLE_ID, "", "",
NULL,
G_PARAM_READWRITE |
NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS));
/** /**
* NMSettingConnection:interface-name: * NMSettingConnection:interface-name:
* *

View file

@ -46,6 +46,7 @@ G_BEGIN_DECLS
#define NM_SETTING_CONNECTION_ID "id" #define NM_SETTING_CONNECTION_ID "id"
#define NM_SETTING_CONNECTION_UUID "uuid" #define NM_SETTING_CONNECTION_UUID "uuid"
#define NM_SETTING_CONNECTION_STABLE_ID "stable-id"
#define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name" #define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name"
#define NM_SETTING_CONNECTION_TYPE "type" #define NM_SETTING_CONNECTION_TYPE "type"
#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect" #define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect"
@ -116,6 +117,8 @@ GType nm_setting_connection_get_type (void);
NMSetting * nm_setting_connection_new (void); NMSetting * nm_setting_connection_new (void);
const char *nm_setting_connection_get_id (NMSettingConnection *setting); const char *nm_setting_connection_get_id (NMSettingConnection *setting);
const char *nm_setting_connection_get_uuid (NMSettingConnection *setting); const char *nm_setting_connection_get_uuid (NMSettingConnection *setting);
NM_AVAILABLE_IN_1_4
const char *nm_setting_connection_get_stable_id (NMSettingConnection *setting);
const char *nm_setting_connection_get_interface_name (NMSettingConnection *setting); const char *nm_setting_connection_get_interface_name (NMSettingConnection *setting);
const char *nm_setting_connection_get_connection_type (NMSettingConnection *setting); const char *nm_setting_connection_get_connection_type (NMSettingConnection *setting);
gboolean nm_setting_connection_get_autoconnect (NMSettingConnection *setting); gboolean nm_setting_connection_get_autoconnect (NMSettingConnection *setting);

View file

@ -299,6 +299,52 @@ nm_ip_address_unref (NMIPAddress *address)
} }
} }
/**
* _nm_ip_address_equal:
* @address: the #NMIPAddress
* @other: the #NMIPAddress to compare @address to.
* @consider_attributes: whether to check for equality of attributes too.
*
* Determines if two #NMIPAddress objects are equal.
*
* Returns: %TRUE if the objects contain the same values, %FALSE if they do not.
**/
static gboolean
_nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other, gboolean consider_attributes)
{
g_return_val_if_fail (address != NULL, FALSE);
g_return_val_if_fail (address->refcount > 0, FALSE);
g_return_val_if_fail (other != NULL, FALSE);
g_return_val_if_fail (other->refcount > 0, FALSE);
if ( address->family != other->family
|| address->prefix != other->prefix
|| strcmp (address->address, other->address) != 0)
return FALSE;
if (consider_attributes) {
GHashTableIter iter;
const char *key;
GVariant *value, *value2;
guint n;
n = address->attributes ? g_hash_table_size (address->attributes) : 0;
if (n != (other->attributes ? g_hash_table_size (other->attributes) : 0))
return FALSE;
if (n) {
g_hash_table_iter_init (&iter, address->attributes);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
value2 = g_hash_table_lookup (other->attributes, key);
if (!value2)
return FALSE;
if (!g_variant_equal (value, value2))
return FALSE;
}
}
}
return TRUE;
}
/** /**
* nm_ip_address_equal: * nm_ip_address_equal:
* @address: the #NMIPAddress * @address: the #NMIPAddress
@ -312,17 +358,7 @@ nm_ip_address_unref (NMIPAddress *address)
gboolean gboolean
nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other) nm_ip_address_equal (NMIPAddress *address, NMIPAddress *other)
{ {
g_return_val_if_fail (address != NULL, FALSE); return _nm_ip_address_equal (address, other, FALSE);
g_return_val_if_fail (address->refcount > 0, FALSE);
g_return_val_if_fail (other != NULL, FALSE);
g_return_val_if_fail (other->refcount > 0, FALSE);
if ( address->family != other->family
|| address->prefix != other->prefix
|| strcmp (address->address, other->address) != 0)
return FALSE;
return TRUE;
} }
/** /**
@ -717,17 +753,18 @@ nm_ip_route_unref (NMIPRoute *route)
} }
/** /**
* nm_ip_route_equal: * _nm_ip_route_equal:
* @route: the #NMIPRoute * @route: the #NMIPRoute
* @other: the #NMIPRoute to compare @route to. * @other: the #NMIPRoute to compare @route to.
* @consider_attributes: whether to compare attributes too
* *
* Determines if two #NMIPRoute objects contain the same destination, prefix, * Determines if two #NMIPRoute objects contain the same destination, prefix,
* next hop, and metric. (Attributes are not compared.) * next hop, and metric.
* *
* Returns: %TRUE if the objects contain the same values, %FALSE if they do not. * Returns: %TRUE if the objects contain the same values, %FALSE if they do not.
**/ **/
gboolean static gboolean
nm_ip_route_equal (NMIPRoute *route, NMIPRoute *other) _nm_ip_route_equal (NMIPRoute *route, NMIPRoute *other, gboolean consider_attributes)
{ {
g_return_val_if_fail (route != NULL, FALSE); g_return_val_if_fail (route != NULL, FALSE);
g_return_val_if_fail (route->refcount > 0, FALSE); g_return_val_if_fail (route->refcount > 0, FALSE);
@ -740,9 +777,45 @@ nm_ip_route_equal (NMIPRoute *route, NMIPRoute *other)
|| strcmp (route->dest, other->dest) != 0 || strcmp (route->dest, other->dest) != 0
|| g_strcmp0 (route->next_hop, other->next_hop) != 0) || g_strcmp0 (route->next_hop, other->next_hop) != 0)
return FALSE; return FALSE;
if (consider_attributes) {
GHashTableIter iter;
const char *key;
GVariant *value, *value2;
guint n;
n = route->attributes ? g_hash_table_size (route->attributes) : 0;
if (n != (other->attributes ? g_hash_table_size (other->attributes) : 0))
return FALSE;
if (n) {
g_hash_table_iter_init (&iter, route->attributes);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
value2 = g_hash_table_lookup (other->attributes, key);
if (!value2)
return FALSE;
if (!g_variant_equal (value, value2))
return FALSE;
}
}
}
return TRUE; return TRUE;
} }
/**
* nm_ip_route_equal:
* @route: the #NMIPRoute
* @other: the #NMIPRoute to compare @route to.
*
* Determines if two #NMIPRoute objects contain the same destination, prefix,
* next hop, and metric. (Attributes are not compared.)
*
* Returns: %TRUE if the objects contain the same values, %FALSE if they do not.
**/
gboolean
nm_ip_route_equal (NMIPRoute *route, NMIPRoute *other)
{
return _nm_ip_route_equal (route, other, FALSE);
}
/** /**
* nm_ip_route_dup: * nm_ip_route_dup:
* @route: the #NMIPRoute * @route: the #NMIPRoute
@ -2306,6 +2379,48 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE; return TRUE;
} }
static gboolean
compare_property (NMSetting *setting,
NMSetting *other,
const GParamSpec *prop_spec,
NMSettingCompareFlags flags)
{
NMSettingIPConfigPrivate *a_priv, *b_priv;
NMSettingClass *parent_class;
guint i;
if (nm_streq (prop_spec->name, NM_SETTING_IP_CONFIG_ADDRESSES)) {
a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
if (a_priv->addresses->len != b_priv->addresses->len)
return FALSE;
for (i = 0; i < a_priv->addresses->len; i++) {
if (!_nm_ip_address_equal (a_priv->addresses->pdata[i], b_priv->addresses->pdata[i], TRUE))
return FALSE;
}
return TRUE;
}
if (nm_streq (prop_spec->name, NM_SETTING_IP_CONFIG_ROUTES)) {
a_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
b_priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (other);
if (a_priv->routes->len != b_priv->routes->len)
return FALSE;
for (i = 0; i < a_priv->routes->len; i++) {
if (!_nm_ip_route_equal (a_priv->routes->pdata[i], b_priv->routes->pdata[i], TRUE))
return FALSE;
}
return TRUE;
}
/* Otherwise chain up to parent to handle generic compare */
parent_class = NM_SETTING_CLASS (nm_setting_ip_config_parent_class);
return parent_class->compare_property (setting, other, prop_spec, flags);
}
/*****************************************************************************/
static void static void
nm_setting_ip_config_init (NMSettingIPConfig *setting) nm_setting_ip_config_init (NMSettingIPConfig *setting)
@ -2536,6 +2651,7 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->verify = verify; parent_class->verify = verify;
parent_class->compare_property = compare_property;
/* Properties */ /* Properties */

View file

@ -28,6 +28,7 @@
#include <net/ethernet.h> #include <net/ethernet.h>
#include "nm-utils.h" #include "nm-utils.h"
#include "nm-common-macros.h"
#include "nm-utils-private.h" #include "nm-utils-private.h"
#include "nm-setting-private.h" #include "nm-setting-private.h"
@ -52,6 +53,7 @@ typedef struct {
gboolean auto_negotiate; gboolean auto_negotiate;
char *device_mac_address; char *device_mac_address;
char *cloned_mac_address; char *cloned_mac_address;
char *generate_mac_address_mask;
GArray *mac_address_blacklist; GArray *mac_address_blacklist;
guint32 mtu; guint32 mtu;
char **s390_subchannels; char **s390_subchannels;
@ -69,6 +71,7 @@ enum {
PROP_AUTO_NEGOTIATE, PROP_AUTO_NEGOTIATE,
PROP_MAC_ADDRESS, PROP_MAC_ADDRESS,
PROP_CLONED_MAC_ADDRESS, PROP_CLONED_MAC_ADDRESS,
PROP_GENERATE_MAC_ADDRESS_MASK,
PROP_MAC_ADDRESS_BLACKLIST, PROP_MAC_ADDRESS_BLACKLIST,
PROP_MTU, PROP_MTU,
PROP_S390_SUBCHANNELS, PROP_S390_SUBCHANNELS,
@ -187,6 +190,22 @@ nm_setting_wired_get_cloned_mac_address (NMSettingWired *setting)
return NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address; 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: * nm_setting_wired_get_mac_address_blacklist:
* @setting: the #NMSettingWired * @setting: the #NMSettingWired
@ -611,6 +630,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
GHashTableIter iter; GHashTableIter iter;
const char *key, *value; const char *key, *value;
int i; int i;
GError *local = NULL;
if (priv->port && !g_strv_contains (valid_ports, priv->port)) { if (priv->port && !g_strv_contains (valid_ports, priv->port)) {
g_set_error (error, 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, g_set_error_literal (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY, NM_CONNECTION_ERROR_INVALID_PROPERTY,
@ -701,6 +723,20 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE; 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) if ( NM_FLAGS_ANY (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS)
&& !nm_utils_is_power_of_two (priv->wol)) { && !nm_utils_is_power_of_two (priv->wol)) {
g_set_error_literal (error, g_set_error_literal (error,
@ -732,6 +768,25 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return TRUE; 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 static void
clear_blacklist_item (char **item_p) clear_blacklist_item (char **item_p)
{ {
@ -763,6 +818,7 @@ finalize (GObject *object)
g_free (priv->device_mac_address); g_free (priv->device_mac_address);
g_free (priv->cloned_mac_address); g_free (priv->cloned_mac_address);
g_free (priv->generate_mac_address_mask);
g_array_unref (priv->mac_address_blacklist); g_array_unref (priv->mac_address_blacklist);
if (priv->s390_subchannels) 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), priv->cloned_mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
ETH_ALEN); ETH_ALEN);
break; 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: case PROP_MAC_ADDRESS_BLACKLIST:
blacklist = g_value_get_boxed (value); blacklist = g_value_get_boxed (value);
g_array_set_size (priv->mac_address_blacklist, 0); 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: case PROP_CLONED_MAC_ADDRESS:
g_value_set_string (value, nm_setting_wired_get_cloned_mac_address (setting)); g_value_set_string (value, nm_setting_wired_get_cloned_mac_address (setting));
break; 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: case PROP_MAC_ADDRESS_BLACKLIST:
g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data); g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
break; break;
@ -900,18 +963,19 @@ get_property (GObject *object, guint prop_id,
} }
static void 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); GObjectClass *object_class = G_OBJECT_CLASS (setting_wired_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_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 */ /* virtual methods */
object_class->set_property = set_property; object_class->set_property = set_property;
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->verify = verify; setting_class->verify = verify;
setting_class->compare_property = compare_property;
/* Properties */ /* Properties */
/** /**
@ -1023,7 +1087,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE | NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS)); 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, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_to_dbus,
_nm_utils_hwaddr_from_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 * If specified, request that the device use this MAC address instead of its
* permanent MAC address. This is known as MAC cloning or spoofing. * 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--- /* ---keyfile---
* property: cloned-mac-address * 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 * description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons
* notation (e.g. 00:22:68:14:5A:99). * notation (e.g. 00:22:68:14:5A:99).
* ---end--- * ---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 g_object_class_install_property
(object_class, PROP_CLONED_MAC_ADDRESS, (object_class, PROP_CLONED_MAC_ADDRESS,
@ -1055,10 +1139,75 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE | NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, _nm_setting_class_override_property (setting_class,
NM_SETTING_WIRED_CLONED_MAC_ADDRESS,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_cloned_get,
_nm_utils_hwaddr_from_dbus); _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", "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: * NMSettingWired:mac-address-blacklist:
@ -1183,7 +1332,7 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class)
G_PARAM_READWRITE | G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE | NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS)); 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}"), G_VARIANT_TYPE ("a{ss}"),
_nm_utils_strdict_to_dbus, _nm_utils_strdict_to_dbus,
_nm_utils_strdict_from_dbus); _nm_utils_strdict_from_dbus);

View file

@ -85,6 +85,7 @@ typedef enum { /*< flags >*/
#define NM_SETTING_WIRED_AUTO_NEGOTIATE "auto-negotiate" #define NM_SETTING_WIRED_AUTO_NEGOTIATE "auto-negotiate"
#define NM_SETTING_WIRED_MAC_ADDRESS "mac-address" #define NM_SETTING_WIRED_MAC_ADDRESS "mac-address"
#define NM_SETTING_WIRED_CLONED_MAC_ADDRESS "cloned-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_MAC_ADDRESS_BLACKLIST "mac-address-blacklist"
#define NM_SETTING_WIRED_MTU "mtu" #define NM_SETTING_WIRED_MTU "mtu"
#define NM_SETTING_WIRED_S390_SUBCHANNELS "s390-subchannels" #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_mac_address (NMSettingWired *setting);
const char * nm_setting_wired_get_cloned_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); const char * const *nm_setting_wired_get_mac_address_blacklist (NMSettingWired *setting);
guint32 nm_setting_wired_get_num_mac_blacklist_items (NMSettingWired *setting); guint32 nm_setting_wired_get_num_mac_blacklist_items (NMSettingWired *setting);
const char * nm_setting_wired_get_mac_blacklist_item (NMSettingWired *setting, const char * nm_setting_wired_get_mac_blacklist_item (NMSettingWired *setting,

View file

@ -22,11 +22,13 @@
#include "nm-default.h" #include "nm-default.h"
#include "nm-setting-wireless.h"
#include <string.h> #include <string.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include "nm-setting-wireless.h"
#include "nm-utils.h" #include "nm-utils.h"
#include "nm-common-macros.h"
#include "nm-utils-private.h" #include "nm-utils-private.h"
#include "nm-setting-private.h" #include "nm-setting-private.h"
@ -54,6 +56,7 @@ typedef struct {
guint32 tx_power; guint32 tx_power;
char *device_mac_address; char *device_mac_address;
char *cloned_mac_address; char *cloned_mac_address;
char *generate_mac_address_mask;
GArray *mac_address_blacklist; GArray *mac_address_blacklist;
guint32 mtu; guint32 mtu;
GSList *seen_bssids; GSList *seen_bssids;
@ -73,6 +76,7 @@ enum {
PROP_TX_POWER, PROP_TX_POWER,
PROP_MAC_ADDRESS, PROP_MAC_ADDRESS,
PROP_CLONED_MAC_ADDRESS, PROP_CLONED_MAC_ADDRESS,
PROP_GENERATE_MAC_ADDRESS_MASK,
PROP_MAC_ADDRESS_BLACKLIST, PROP_MAC_ADDRESS_BLACKLIST,
PROP_MTU, PROP_MTU,
PROP_SEEN_BSSIDS, PROP_SEEN_BSSIDS,
@ -419,6 +423,22 @@ nm_setting_wireless_get_cloned_mac_address (NMSettingWireless *setting)
return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address; 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: * nm_setting_wireless_get_mac_address_blacklist:
* @setting: the #NMSettingWireless * @setting: the #NMSettingWireless
@ -721,6 +741,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
GSList *iter; GSList *iter;
int i; int i;
gsize length; gsize length;
GError *local = NULL;
if (!priv->ssid) { if (!priv->ssid) {
g_set_error_literal (error, g_set_error_literal (error,
@ -801,7 +822,9 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE; return FALSE;
} }
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, g_set_error_literal (error,
NM_CONNECTION_ERROR, NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY, NM_CONNECTION_ERROR_INVALID_PROPERTY,
@ -810,6 +833,20 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE; 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++) { for (i = 0; i < priv->mac_address_blacklist->len; i++) {
const char *mac = g_array_index (priv->mac_address_blacklist, const char *, i); const char *mac = g_array_index (priv->mac_address_blacklist, const char *, i);
@ -836,9 +873,61 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
} }
} }
if (!NM_IN_SET (priv->mac_address_randomization,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
NM_SETTING_MAC_RANDOMIZATION_NEVER,
NM_SETTING_MAC_RANDOMIZATION_ALWAYS)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("invalid value"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION);
return FALSE;
}
/* from here on, check for NM_SETTING_VERIFY_NORMALIZABLE conditions. */
if (priv->cloned_mac_address) {
if ( priv->mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_ALWAYS
&& nm_streq (priv->cloned_mac_address, "random"))
goto mac_addr_rand_ok;
if ( priv->mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_NEVER
&& nm_streq (priv->cloned_mac_address, "permanent"))
goto mac_addr_rand_ok;
if (priv->mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT)
goto mac_addr_rand_ok;
} else if (priv->mac_address_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT)
goto mac_addr_rand_ok;
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("conflicting value of mac-address-randomization and cloned-mac-address"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS);
return NM_SETTING_VERIFY_NORMALIZABLE;
mac_addr_rand_ok:
return TRUE; 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_WIRELESS_CLONED_MAC_ADDRESS)) {
return nm_streq0 (NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address,
NM_SETTING_WIRELESS_GET_PRIVATE (other)->cloned_mac_address);
}
parent_class = NM_SETTING_CLASS (nm_setting_wireless_parent_class);
return parent_class->compare_property (setting, other, prop_spec, flags);
}
/*****************************************************************************/
static GVariant * static GVariant *
nm_setting_wireless_get_security (NMSetting *setting, nm_setting_wireless_get_security (NMSetting *setting,
NMConnection *connection, NMConnection *connection,
@ -879,6 +968,7 @@ finalize (GObject *object)
g_free (priv->bssid); g_free (priv->bssid);
g_free (priv->device_mac_address); g_free (priv->device_mac_address);
g_free (priv->cloned_mac_address); g_free (priv->cloned_mac_address);
g_free (priv->generate_mac_address_mask);
g_array_unref (priv->mac_address_blacklist); g_array_unref (priv->mac_address_blacklist);
g_slist_free_full (priv->seen_bssids, g_free); g_slist_free_full (priv->seen_bssids, g_free);
@ -931,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), priv->cloned_mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
ETH_ALEN); ETH_ALEN);
break; 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: case PROP_MAC_ADDRESS_BLACKLIST:
blacklist = g_value_get_boxed (value); blacklist = g_value_get_boxed (value);
g_array_set_size (priv->mac_address_blacklist, 0); g_array_set_size (priv->mac_address_blacklist, 0);
@ -998,6 +1092,9 @@ get_property (GObject *object, guint prop_id,
case PROP_CLONED_MAC_ADDRESS: case PROP_CLONED_MAC_ADDRESS:
g_value_set_string (value, nm_setting_wireless_get_cloned_mac_address (setting)); g_value_set_string (value, nm_setting_wireless_get_cloned_mac_address (setting));
break; 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: case PROP_MAC_ADDRESS_BLACKLIST:
g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data); g_value_set_boxed (value, (char **) priv->mac_address_blacklist->data);
break; break;
@ -1023,18 +1120,19 @@ get_property (GObject *object, guint prop_id,
} }
static void static void
nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class) nm_setting_wireless_class_init (NMSettingWirelessClass *setting_wireless_class)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (setting_class); GObjectClass *object_class = G_OBJECT_CLASS (setting_wireless_class);
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); NMSettingClass *setting_class = NM_SETTING_CLASS (setting_wireless_class);
g_type_class_add_private (setting_class, sizeof (NMSettingWirelessPrivate)); g_type_class_add_private (setting_wireless_class, sizeof (NMSettingWirelessPrivate));
/* virtual methods */ /* virtual methods */
object_class->set_property = set_property; object_class->set_property = set_property;
object_class->get_property = get_property; object_class->get_property = get_property;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->verify = verify; setting_class->verify = verify;
setting_class->compare_property = compare_property;
/* Properties */ /* Properties */
/** /**
@ -1154,7 +1252,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRELESS_BSSID, _nm_setting_class_transform_property (setting_class, NM_SETTING_WIRELESS_BSSID,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_to_dbus,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_from_dbus);
@ -1231,7 +1329,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRELESS_MAC_ADDRESS, _nm_setting_class_transform_property (setting_class, NM_SETTING_WIRELESS_MAC_ADDRESS,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_to_dbus,
_nm_utils_hwaddr_from_dbus); _nm_utils_hwaddr_from_dbus);
@ -1239,8 +1337,22 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
/** /**
* NMSettingWireless:cloned-mac-address: * NMSettingWireless:cloned-mac-address:
* *
* If specified, request that the Wi-Fi device use this MAC address instead * If specified, request that the device use this MAC address instead of its
* of its permanent MAC address. This is known as MAC cloning or spoofing. * 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--- /* ---keyfile---
* property: cloned-mac-address * property: cloned-mac-address
@ -1255,6 +1367,12 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
* description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons * description: Cloned (spoofed) MAC address in traditional hex-digits-and-colons
* notation (e.g. 00:22:68:14:5A:99). * notation (e.g. 00:22:68:14:5A:99).
* ---end--- * ---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 g_object_class_install_property
(object_class, PROP_CLONED_MAC_ADDRESS, (object_class, PROP_CLONED_MAC_ADDRESS,
@ -1262,10 +1380,75 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
_nm_setting_class_transform_property (parent_class, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, _nm_setting_class_override_property (setting_class,
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS,
G_VARIANT_TYPE_BYTESTRING, G_VARIANT_TYPE_BYTESTRING,
_nm_utils_hwaddr_to_dbus, _nm_utils_hwaddr_cloned_get,
_nm_utils_hwaddr_from_dbus); _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", "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);
/**
* 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: * NMSettingWireless:mac-address-blacklist:
@ -1398,6 +1581,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
* (always randomize the MAC address). * (always randomize the MAC address).
* *
* Since: 1.2 * Since: 1.2
* Deprecated: 1.4: Deprecated by NMSettingWireless:cloned-mac-address property
**/ **/
/* ---ifcfg-rh--- /* ---ifcfg-rh---
* property: mac-address-randomization * property: mac-address-randomization
@ -1428,7 +1612,7 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
* NetworkManager daemons. * NetworkManager daemons.
* ---end--- * ---end---
*/ */
_nm_setting_class_add_dbus_only_property (parent_class, "security", _nm_setting_class_add_dbus_only_property (setting_class, "security",
G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_STRING,
nm_setting_wireless_get_security, NULL); nm_setting_wireless_get_security, NULL);
} }

View file

@ -50,6 +50,7 @@ G_BEGIN_DECLS
#define NM_SETTING_WIRELESS_TX_POWER "tx-power" #define NM_SETTING_WIRELESS_TX_POWER "tx-power"
#define NM_SETTING_WIRELESS_MAC_ADDRESS "mac-address" #define NM_SETTING_WIRELESS_MAC_ADDRESS "mac-address"
#define NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS "cloned-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_MAC_ADDRESS_BLACKLIST "mac-address-blacklist"
#define NM_SETTING_WIRELESS_MTU "mtu" #define NM_SETTING_WIRELESS_MTU "mtu"
#define NM_SETTING_WIRELESS_SEEN_BSSIDS "seen-bssids" #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_mac_address (NMSettingWireless *setting);
const char *nm_setting_wireless_get_cloned_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); const char * const *nm_setting_wireless_get_mac_address_blacklist (NMSettingWireless *setting);
guint32 nm_setting_wireless_get_num_mac_blacklist_items (NMSettingWireless *setting); guint32 nm_setting_wireless_get_num_mac_blacklist_items (NMSettingWireless *setting);
const char * nm_setting_wireless_get_mac_blacklist_item (NMSettingWireless *setting, const char * nm_setting_wireless_get_mac_blacklist_item (NMSettingWireless *setting,

View file

@ -36,6 +36,29 @@ gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, g
/* D-Bus transform funcs */ /* D-Bus transform funcs */
GVariant *_nm_utils_hwaddr_cloned_get (NMSetting *setting,
const char *property);
gboolean _nm_utils_hwaddr_cloned_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error);
gboolean _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
NMSettingParseFlags parse_flags,
GError **error);
GVariant * _nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
NMConnection *connection,
const char *property);
gboolean _nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error);
GVariant * _nm_utils_hwaddr_to_dbus (const GValue *prop_value); GVariant * _nm_utils_hwaddr_to_dbus (const GValue *prop_value);
void _nm_utils_hwaddr_from_dbus (GVariant *dbus_value, void _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
GValue *prop_value); GValue *prop_value);

View file

@ -37,6 +37,7 @@
#include <jansson.h> #include <jansson.h>
#endif #endif
#include "nm-common-macros.h"
#include "nm-utils-private.h" #include "nm-utils-private.h"
#include "nm-setting-private.h" #include "nm-setting-private.h"
#include "crypto.h" #include "crypto.h"
@ -3114,6 +3115,33 @@ hwaddr_binary_len (const char *asc)
return octets; return octets;
} }
/**
* _nm_utils_hwaddr_length:
* @asc: the ASCII representation of the hardware address
*
* Validates that @asc is a valid representation of a hardware
* address up to (including) %NM_UTILS_HWADDR_LEN_MAX bytes.
*
* Returns: binary length of the hardware address @asc or
* 0 on error.
*/
guint
_nm_utils_hwaddr_length (const char *asc)
{
int l;
if (!asc)
return 0;
l = hwaddr_binary_len (asc);
if (l <= 0 || l > NM_UTILS_HWADDR_LEN_MAX)
return 0;
if (!nm_utils_hwaddr_valid (asc, l))
return 0;
return l;
}
/** /**
* nm_utils_hwaddr_valid: * nm_utils_hwaddr_valid:
* @asc: the ASCII representation of a hardware address * @asc: the ASCII representation of a hardware address
@ -3286,24 +3314,124 @@ nm_utils_hwaddr_matches (gconstpointer hwaddr1,
return !memcmp (hwaddr1, hwaddr2, hwaddr1_len); return !memcmp (hwaddr1, hwaddr2, hwaddr1_len);
} }
GVariant * /*****************************************************************************/
_nm_utils_hwaddr_to_dbus (const GValue *prop_value)
static GVariant *
_nm_utils_hwaddr_to_dbus_impl (const char *str)
{ {
const char *str = g_value_get_string (prop_value);
guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
int len; int len;
if (str) { if (!str)
len = hwaddr_binary_len (str); return NULL;
g_return_val_if_fail (len > 0 && len <= NM_UTILS_HWADDR_LEN_MAX, NULL);
len = _nm_utils_hwaddr_length (str);
if (len == 0)
return NULL;
if (!nm_utils_hwaddr_aton (str, buf, len)) if (!nm_utils_hwaddr_aton (str, buf, len))
len = 0; return NULL;
} else
len = 0;
return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1); return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
} }
GVariant *
_nm_utils_hwaddr_cloned_get (NMSetting *setting,
const char *property)
{
gs_free char *addr = NULL;
nm_assert (nm_streq0 (property, "cloned-mac-address"));
g_object_get (setting, "cloned-mac-address", &addr, NULL);
return _nm_utils_hwaddr_to_dbus_impl (addr);
}
gboolean
_nm_utils_hwaddr_cloned_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error)
{
gsize length;
const guint8 *array;
char *str;
nm_assert (nm_streq0 (property, "cloned-mac-address"));
if (!_nm_setting_use_legacy_property (setting, connection_dict, "cloned-mac-address", "assigned-mac-address"))
return TRUE;
length = 0;
array = g_variant_get_fixed_array (value, &length, 1);
if (!length)
return TRUE;
str = nm_utils_hwaddr_ntoa (array, length);
g_object_set (setting,
"cloned-mac-address",
str,
NULL);
g_free (str);
return TRUE;
}
gboolean
_nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
NMSettingParseFlags parse_flags,
GError **error)
{
nm_assert (nm_streq0 (property, "cloned-mac-address"));
return TRUE;
}
GVariant *
_nm_utils_hwaddr_cloned_data_synth (NMSetting *setting,
NMConnection *connection,
const char *property)
{
gs_free char *addr = NULL;
nm_assert (nm_streq0 (property, "assigned-mac-address"));
g_object_get (setting,
"cloned-mac-address",
&addr,
NULL);
return addr ? g_variant_new_string (addr) : NULL;
}
gboolean
_nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error)
{
nm_assert (nm_streq0 (property, "assigned-mac-address"));
if (_nm_setting_use_legacy_property (setting, connection_dict, "cloned-mac-address", "assigned-mac-address"))
return TRUE;
g_object_set (setting,
"cloned-mac-address",
g_variant_get_string (value, NULL),
NULL);
return TRUE;
}
GVariant *
_nm_utils_hwaddr_to_dbus (const GValue *prop_value)
{
return _nm_utils_hwaddr_to_dbus_impl (g_value_get_string (prop_value));
}
void void
_nm_utils_hwaddr_from_dbus (GVariant *dbus_value, _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
GValue *prop_value) GValue *prop_value)
@ -3316,6 +3444,93 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
g_value_take_string (prop_value, str); g_value_take_string (prop_value, str);
} }
/*****************************************************************************/
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: * nm_utils_bin2hexstr:
* @src: (type guint8) (array length=len): an array of bytes * @src: (type guint8) (array length=len): an array of bytes

View file

@ -1916,6 +1916,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_CONNECTION_SETTING_NAME, { { NM_SETTING_CONNECTION_SETTING_NAME, {
{ NM_SETTING_CONNECTION_ID, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_ID, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_UUID, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_UUID, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_STABLE_ID, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_TYPE, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_TYPE, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_TIMESTAMP, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_TIMESTAMP, NM_SETTING_DIFF_RESULT_IN_A },
@ -1940,6 +1941,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_WIRED_AUTO_NEGOTIATE, NM_SETTING_DIFF_RESULT_IN_A }, { 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_MAC_ADDRESS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_CLONED_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_MAC_ADDRESS_BLACKLIST, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_WIRED_MTU, 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 }, { NM_SETTING_WIRED_S390_SUBCHANNELS, NM_SETTING_DIFF_RESULT_IN_A },
@ -2384,6 +2386,154 @@ test_setting_compare_id (void)
g_assert (success); g_assert (success);
} }
static void
test_setting_compare_addresses (void)
{
gs_unref_object NMSetting *s1 = NULL, *s2 = NULL;
gboolean success;
NMIPAddress *a;
GHashTable *result = NULL;
s1 = nm_setting_ip4_config_new ();
s2 = nm_setting_ip4_config_new ();
a = nm_ip_address_new (AF_INET, "192.168.7.5", 24, NULL);
nm_ip_address_set_attribute (a, "label", g_variant_new_string ("xoxoxo"));
nm_setting_ip_config_add_address ((NMSettingIPConfig *) s1, a);
nm_ip_address_set_attribute (a, "label", g_variant_new_string ("hello"));
nm_setting_ip_config_add_address ((NMSettingIPConfig *) s2, a);
nm_ip_address_unref (a);
if (nmtst_get_rand_int () % 2)
NMTST_SWAP (s1, s2);
success = nm_setting_compare (s1, s2, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
success = nm_setting_diff (s1, s2, NM_SETTING_COMPARE_FLAG_EXACT, FALSE, &result);
g_assert (!success);
g_clear_pointer (&result, g_hash_table_unref);
}
static void
test_setting_compare_routes (void)
{
gs_unref_object NMSetting *s1 = NULL, *s2 = NULL;
gboolean success;
NMIPRoute *r;
GHashTable *result = NULL;
s1 = nm_setting_ip4_config_new ();
s2 = nm_setting_ip4_config_new ();
r = nm_ip_route_new (AF_INET, "192.168.12.0", 24, "192.168.11.1", 473, NULL);
nm_ip_route_set_attribute (r, "label", g_variant_new_string ("xoxoxo"));
nm_setting_ip_config_add_route ((NMSettingIPConfig *) s1, r);
nm_ip_route_set_attribute (r, "label", g_variant_new_string ("hello"));
nm_setting_ip_config_add_route ((NMSettingIPConfig *) s2, r);
nm_ip_route_unref (r);
if (nmtst_get_rand_int () % 2)
NMTST_SWAP (s1, s2);
success = nm_setting_compare (s1, s2, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
success = nm_setting_diff (s1, s2, NM_SETTING_COMPARE_FLAG_EXACT, FALSE, &result);
g_assert (!success);
g_clear_pointer (&result, g_hash_table_unref);
}
static void
test_setting_compare_wired_cloned_mac_address (void)
{
gs_unref_object NMSetting *old = NULL, *new = NULL;
gboolean success;
gs_free char *str1 = NULL;
old = nm_setting_wired_new ();
g_object_set (old,
NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "stable",
NULL);
g_assert_cmpstr ("stable", ==, nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) old));
g_object_get (old, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable", ==, str1);
g_clear_pointer (&str1, g_free);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "11:22:33:44:55:66", NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) new));
g_object_get (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, "stable-bia", NULL);
g_assert_cmpstr ("stable-bia", ==, nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) new));
g_object_get (new, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable-bia", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
}
static void
test_setting_compare_wireless_cloned_mac_address (void)
{
gs_unref_object NMSetting *old = NULL, *new = NULL;
gboolean success;
gs_free char *str1 = NULL;
old = nm_setting_wireless_new ();
g_object_set (old,
NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "stable",
NULL);
g_assert_cmpstr ("stable", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) old));
g_object_get (old, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable", ==, str1);
g_clear_pointer (&str1, g_free);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "11:22:33:44:55:66", NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) new));
g_object_get (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("11:22:33:44:55:66", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
new = nm_setting_duplicate (old);
g_object_set (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, "stable-bia", NULL);
g_assert_cmpstr ("stable-bia", ==, nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) new));
g_object_get (new, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, &str1, NULL);
g_assert_cmpstr ("stable-bia", ==, str1);
g_clear_pointer (&str1, g_free);
success = nm_setting_compare (old, new, NM_SETTING_COMPARE_FLAG_EXACT);
g_assert (!success);
g_clear_object (&new);
}
static void static void
test_setting_compare_timestamp (void) test_setting_compare_timestamp (void)
{ {
@ -5135,6 +5285,10 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/test_setting_to_dbus_transform", test_setting_to_dbus_transform); g_test_add_func ("/core/general/test_setting_to_dbus_transform", test_setting_to_dbus_transform);
g_test_add_func ("/core/general/test_setting_to_dbus_enum", test_setting_to_dbus_enum); g_test_add_func ("/core/general/test_setting_to_dbus_enum", test_setting_to_dbus_enum);
g_test_add_func ("/core/general/test_setting_compare_id", test_setting_compare_id); g_test_add_func ("/core/general/test_setting_compare_id", test_setting_compare_id);
g_test_add_func ("/core/general/test_setting_compare_addresses", test_setting_compare_addresses);
g_test_add_func ("/core/general/test_setting_compare_routes", test_setting_compare_routes);
g_test_add_func ("/core/general/test_setting_compare_wired_cloned_mac_address", test_setting_compare_wired_cloned_mac_address);
g_test_add_func ("/core/general/test_setting_compare_wirless_cloned_mac_address", test_setting_compare_wireless_cloned_mac_address);
g_test_add_func ("/core/general/test_setting_compare_timestamp", test_setting_compare_timestamp); g_test_add_func ("/core/general/test_setting_compare_timestamp", test_setting_compare_timestamp);
#define ADD_FUNC(name, func, secret_flags, comp_flags, remove_secret) \ #define ADD_FUNC(name, func, secret_flags, comp_flags, remove_secret) \
g_test_add_data_func_full ("/core/general/" G_STRINGIFY (func) "_" name, \ g_test_add_data_func_full ("/core/general/" G_STRINGIFY (func) "_" name, \

View file

@ -1066,8 +1066,11 @@ libnm_1_2_4 {
libnm_1_4_0 { libnm_1_4_0 {
global: global:
nm_device_team_get_config; nm_device_team_get_config;
nm_setting_connection_get_stable_id;
nm_setting_ip6_config_get_token; nm_setting_ip6_config_get_token;
nm_setting_ip_config_get_dns_priority; 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_plugin_info;
nm_vpn_editor_plugin_get_vt; nm_vpn_editor_plugin_get_vt;
nm_vpn_editor_plugin_load; nm_vpn_editor_plugin_load;

View file

@ -224,30 +224,12 @@ no-auto-default=*
<term><varname>ignore-carrier</varname></term> <term><varname>ignore-carrier</varname></term>
<listitem> <listitem>
<para> <para>
Specify devices for which NetworkManager will (partially) This setting is deprecated for the per-device setting
ignore the carrier state. Normally, for <literal>ignore-carrier</literal> which overwrites this setting
device types that support carrier-detect, such as Ethernet if specified (See <xref linked="ignore-carrier"/>).
and InfiniBand, NetworkManager will only allow a Otherwise, it is a list of matches to specify for which device
connection to be activated on the device if carrier is carrier should be ignored. See <xref linkend="device-spec"/> for the
present (ie, a cable is plugged in), and it will syntax how to specify a device.
deactivate the device if carrier drops for more than a few
seconds.
</para>
<para>
Listing a device here will allow activating connections on
that device even when it does not have carrier, provided
that the connection uses only statically-configured IP
addresses. Additionally, it will allow any active
connection (whether static or dynamic) to remain active on
the device when carrier is lost.
</para>
<para>
Note that the "carrier" property of NMDevices and device D-Bus
interfaces will still reflect the actual device state; it's just
that NetworkManager will not make use of that information.
</para>
<para>See <xref linkend="device-spec"/> for the syntax how to
specify a device.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -583,6 +565,13 @@ ipv6.ip6-privacy=0
<varlistentry> <varlistentry>
<term><varname>connection.lldp</varname></term> <term><varname>connection.lldp</varname></term>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ethernet.cloned-mac-address</varname></term>
<listitem><para>If left unspecified, it defaults to "permanent".</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ethernet.generate-mac-address-mask</varname></term>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>ethernet.wake-on-lan</varname></term> <term><varname>ethernet.wake-on-lan</varname></term>
</varlistentry> </varlistentry>
@ -610,9 +599,18 @@ ipv6.ip6-privacy=0
<term><varname>vpn.timeout</varname></term> <term><varname>vpn.timeout</varname></term>
<listitem><para>If left unspecified, default value of 60 seconds is used.</para></listitem> <listitem><para>If left unspecified, default value of 60 seconds is used.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>wifi.cloned-mac-address</varname></term>
<listitem><para>If left unspecified, it defaults to "permanent".</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>wifi.generate-mac-address-mask</varname></term>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>wifi.mac-address-randomization</varname></term> <term><varname>wifi.mac-address-randomization</varname></term>
<listitem><para>If left unspecified, MAC address randomization is disabled.</para></listitem> <listitem><para>If left unspecified, MAC address randomization is disabled.
This setting is deprecated for <literal>wifi.cloned-mac-address</literal>.
</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><varname>wifi.powersave</varname></term> <term><varname>wifi.powersave</varname></term>
@ -623,7 +621,7 @@ ipv6.ip6-privacy=0
</para> </para>
</refsect2> </refsect2>
<refsect2> <refsect2 id="connection-sections">
<title>Sections</title> <title>Sections</title>
<para> <para>
You can configure multiple <literal>connection</literal> You can configure multiple <literal>connection</literal>
@ -696,6 +694,97 @@ ipv6.ip6-privacy=1
</refsect2> </refsect2>
</refsect1> </refsect1>
<refsect1>
<title><literal>device</literal> section</title>
<para>Contains per-device persistent configuration.
</para>
<para>
Example:
<programlisting>
[device]
match-device=interface-name:eth3
unmanaged=1
</programlisting>
</para>
<refsect2>
<title>Supported Properties</title>
<para>
The following properties can be configured per-device.
<variablelist>
<varlistentry id="ignore-carrier">
<term><varname>ignore-carrier</varname></term>
<listitem>
<para>
Specify devices for which NetworkManager will (partially)
ignore the carrier state. Normally, for
device types that support carrier-detect, such as Ethernet
and InfiniBand, NetworkManager will only allow a
connection to be activated on the device if carrier is
present (ie, a cable is plugged in), and it will
deactivate the device if carrier drops for more than a few
seconds.
</para>
<para>
A device with carrier ignored will allow activating connections on
that device even when it does not have carrier, provided
that the connection uses only statically-configured IP
addresses. Additionally, it will allow any active
connection (whether static or dynamic) to remain active on
the device when carrier is lost.
</para>
<para>
Note that the "carrier" property of NMDevices and device D-Bus
interfaces will still reflect the actual device state; it's just
that NetworkManager will not make use of that information.
</para>
<para>
This setting overwrites the deprecated <literal>main.ignore-carrier</literal>
setting above.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>wifi.scan-rand-mac-address</varname></term>
<listitem>
<para>
Configures the MAC address of a Wi-Fi device during scanning.
This defaults to <literal>yes</literal> in which case a random,
locally-administered MAC address will be confiugred.
Otherwise, the MAC address is left unchanged to whatever was
configured.
For the MAC address used while the device is connected, see instead
the per-connection setting <literal>wifi.cloned-mac-address</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>wifi.scan-generate-mac-address-mask</varname></term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
<refsect2>
<title>Sections</title>
<para>
The <literal>[device]</literal> section works the same as the <literal>[connection]</literal> section.
That is, multiple sections that all start with the prefix "device" can be specified.
The settings "match-device" and "stop-match" are available to match a device section
on a device. The order of multiple sections is also top-down within the file and
later files overwrite previous settings. See <xref linkend="connection-sections"/>
for details.
</para>
</refsect2>
</refsect1>
<refsect1> <refsect1>
<title><literal>connectivity</literal> section</title> <title><literal>connectivity</literal> section</title>
<para>This section controls NetworkManager's optional connectivity <para>This section controls NetworkManager's optional connectivity
@ -978,7 +1067,8 @@ enable=nm-version-min:1.3,nm-version-min:1.2.6,nm-version-min:1.0.16
<title>Device List Format</title> <title>Device List Format</title>
<para> <para>
The configuration options <literal>main.no-auto-default</literal>, <literal>main.ignore-carrier</literal>, The configuration options <literal>main.no-auto-default</literal>, <literal>main.ignore-carrier</literal>,
and <literal>keyfile.unmanaged-devices</literal> select devices based on a list of matchings. <literal>keyfile.unmanaged-devices</literal>, <literal>connection*.match-device</literal> and
<literal>device*.match-device</literal> select devices based on a list of matchings.
Devices can be specified using the following format: Devices can be specified using the following format:
</para> </para>
<para> <para>
@ -993,7 +1083,7 @@ enable=nm-version-min:1.3,nm-version-min:1.2.6,nm-version-min:1.0.16
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>HWADDR</term> <term>HWADDR</term>
<listitem><para>Match the MAC address of the device. Globbing is not supported</para></listitem> <listitem><para>Match the permanent MAC address of the device. Globbing is not supported</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>interface-name:IFNAME</term> <term>interface-name:IFNAME</term>
@ -1008,7 +1098,7 @@ enable=nm-version-min:1.3,nm-version-min:1.2.6,nm-version-min:1.0.16
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>mac:HWADDR</term> <term>mac:HWADDR</term>
<listitem><para>Match the MAC address of the device. Globbing is not supported</para></listitem> <listitem><para>Match the permanent MAC address of the device. Globbing is not supported</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>s390-subchannels:HWADDR</term> <term>s390-subchannels:HWADDR</term>

View file

@ -257,6 +257,11 @@ DEVICETYPE=TeamPort
assigns the interface 10.42.0.1, or it uses the first static address, assigns the interface 10.42.0.1, or it uses the first static address,
if configured.</para> if configured.</para>
</listitem> </listitem>
<listitem>
<para><literal>HWADDR</literal> -
initscripts compare the currently set hardware address of a device, while
NetworkManager considers the permanent one.</para>
</listitem>
</itemizedlist> </itemizedlist>
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>

View file

@ -38,6 +38,21 @@
#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns" #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns"
#define NM_AUTH_PERMISSION_RELOAD "org.freedesktop.NetworkManager.reload" #define NM_AUTH_PERMISSION_RELOAD "org.freedesktop.NetworkManager.reload"
#define NM_CLONED_MAC_PRESERVE "preserve"
#define NM_CLONED_MAC_PERMANENT "permanent"
#define NM_CLONED_MAC_RANDOM "random"
#define NM_CLONED_MAC_STABLE "stable"
static inline gboolean
NM_CLONED_MAC_IS_SPECIAL (const char *str)
{
return NM_IN_STRSET (str,
NM_CLONED_MAC_PRESERVE,
NM_CLONED_MAC_PERMANENT,
NM_CLONED_MAC_RANDOM,
NM_CLONED_MAC_STABLE);
}
/******************************************************************************/ /******************************************************************************/
#endif /* __NM_COMMON_MACROS_H__ */ #endif /* __NM_COMMON_MACROS_H__ */

View file

@ -551,6 +551,12 @@ check_connection_cloned_mac_address (NMConnection *orig,
if (s_wired_cand) if (s_wired_cand)
cand_mac = nm_setting_wired_get_cloned_mac_address (s_wired_cand); cand_mac = nm_setting_wired_get_cloned_mac_address (s_wired_cand);
/* special cloned mac address entires are accepted. */
if (NM_CLONED_MAC_IS_SPECIAL (orig_mac))
orig_mac = NULL;
if (NM_CLONED_MAC_IS_SPECIAL (cand_mac))
cand_mac = NULL;
if (!orig_mac || !cand_mac) { if (!orig_mac || !cand_mac) {
remove_from_hash (settings, props, remove_from_hash (settings, props,
NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_SETTING_NAME,

View file

@ -1002,7 +1002,7 @@ nm_device_bt_new (NMBluezDevice *bt_device,
NM_DEVICE_UDI, udi, NM_DEVICE_UDI, udi,
NM_DEVICE_IFACE, bdaddr, NM_DEVICE_IFACE, bdaddr,
NM_DEVICE_DRIVER, "bluez", NM_DEVICE_DRIVER, "bluez",
NM_DEVICE_HW_ADDRESS, bdaddr, NM_DEVICE_PERM_HW_ADDRESS, bdaddr,
NM_DEVICE_BT_DEVICE, bt_device, NM_DEVICE_BT_DEVICE, bt_device,
NM_DEVICE_BT_NAME, name, NM_DEVICE_BT_NAME, name,
NM_DEVICE_BT_CAPABILITIES, capabilities, NM_DEVICE_BT_CAPABILITIES, capabilities,

View file

@ -120,7 +120,6 @@ typedef struct {
enum { enum {
PROP_0, PROP_0,
PROP_PERM_HW_ADDRESS,
PROP_SPEED, PROP_SPEED,
PROP_S390_SUBCHANNELS, PROP_S390_SUBCHANNELS,
@ -307,14 +306,6 @@ nm_device_ethernet_init (NMDeviceEthernet *self)
priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
} }
static void
realize_start_notify (NMDevice *device, const NMPlatformLink *plink)
{
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->realize_start_notify (device, plink);
g_object_notify (G_OBJECT (device), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS);
}
static NMDeviceCapabilities static NMDeviceCapabilities
get_generic_capabilities (NMDevice *device) get_generic_capabilities (NMDevice *device)
{ {
@ -408,7 +399,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!match_subchans (self, s_wired, &try_mac)) if (!match_subchans (self, s_wired, &try_mac))
return FALSE; return FALSE;
perm_hw_addr = nm_device_get_permanent_hw_address (device); perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
mac = nm_setting_wired_get_mac_address (s_wired); mac = nm_setting_wired_get_mac_address (s_wired);
if (perm_hw_addr) { if (perm_hw_addr) {
if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1))
@ -813,21 +804,17 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{ {
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NMSettingWired *s_wired;
const char *cloned_mac;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason); ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED); if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE))
if (s_wired) { ret = NM_ACT_STAGE_RETURN_FAILURE;
/* Set device MAC address if the connection wants to change it */
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_ETHER);
} }
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
/* If we're re-activating a PPPoE connection a short while after /* If we're re-activating a PPPoE connection a short while after
* a previous PPPoE connection was torn down, wait a bit to allow the * a previous PPPoE connection was torn down, wait a bit to allow the
* remote side to handle the disconnection. Otherwise the peer may * remote side to handle the disconnection. Otherwise the peer may
@ -1365,10 +1352,6 @@ deactivate (NMDevice *device)
/* Set last PPPoE connection time */ /* Set last PPPoE connection time */
if (nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPPOE)) if (nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPPOE))
NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s (); NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s ();
/* Reset MAC address back to initial address */
if (nm_device_get_initial_hw_address (device))
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_ETHER);
} }
static gboolean static gboolean
@ -1409,7 +1392,7 @@ complete_connection (NMDevice *device,
nm_connection_add_setting (connection, NM_SETTING (s_wired)); nm_connection_add_setting (connection, NM_SETTING (s_wired));
} }
perm_hw_addr = nm_device_get_permanent_hw_address (device); perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
if (perm_hw_addr) { if (perm_hw_addr) {
setting_mac = nm_setting_wired_get_mac_address (s_wired); setting_mac = nm_setting_wired_get_mac_address (s_wired);
if (setting_mac) { if (setting_mac) {
@ -1438,7 +1421,7 @@ new_default_connection (NMDevice *self)
NMConnection *connection; NMConnection *connection;
NMSettingsConnection *const*connections; NMSettingsConnection *const*connections;
NMSetting *setting; NMSetting *setting;
const char *hw_address; const char *perm_hw_addr;
gs_free char *defname = NULL; gs_free char *defname = NULL;
gs_free char *uuid = NULL; gs_free char *uuid = NULL;
gs_free char *machine_id = NULL; gs_free char *machine_id = NULL;
@ -1446,8 +1429,8 @@ new_default_connection (NMDevice *self)
if (nm_config_get_no_auto_default_for_device (nm_config_get (), self)) if (nm_config_get_no_auto_default_for_device (nm_config_get (), self))
return NULL; return NULL;
hw_address = nm_device_get_hw_address (self); perm_hw_addr = nm_device_get_permanent_hw_address (self, FALSE);
if (!hw_address) if (!perm_hw_addr)
return NULL; return NULL;
connection = nm_simple_connection_new (); connection = nm_simple_connection_new ();
@ -1466,7 +1449,7 @@ new_default_connection (NMDevice *self)
uuid = _nm_utils_uuid_generate_from_strings ("default-wired", uuid = _nm_utils_uuid_generate_from_strings ("default-wired",
machine_id ?: "", machine_id ?: "",
defname, defname,
hw_address, perm_hw_addr,
NULL); NULL);
g_object_set (setting, g_object_set (setting,
@ -1480,7 +1463,7 @@ new_default_connection (NMDevice *self)
/* Lock the connection to the device */ /* Lock the connection to the device */
setting = nm_setting_wired_new (); setting = nm_setting_wired_new ();
g_object_set (setting, NM_SETTING_WIRED_MAC_ADDRESS, hw_address, NULL); g_object_set (setting, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL);
nm_connection_add_setting (connection, setting); nm_connection_add_setting (connection, setting);
return connection; return connection;
@ -1506,7 +1489,7 @@ update_connection (NMDevice *device, NMConnection *connection)
{ {
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
NMSettingWired *s_wired = nm_connection_get_setting_wired (connection); NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
const char *perm_hw_addr = nm_device_get_permanent_hw_address (device); const char *perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
const char *mac = nm_device_get_hw_address (device); const char *mac = nm_device_get_hw_address (device);
const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS;
GHashTableIter iter; GHashTableIter iter;
@ -1582,34 +1565,10 @@ link_changed (NMDevice *device, NMPlatformLink *info)
{ {
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
const guint8 *hwaddr;
gsize hwaddrlen = 0;
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info); NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
if (!priv->subchan1 && info->initialized) if (!priv->subchan1 && info->initialized)
_update_s390_subchannels (self); _update_s390_subchannels (self);
if (!nm_device_get_initial_hw_address (device)) {
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET,
nm_device_get_ifindex (self),
&hwaddrlen);
if (!nm_utils_hwaddr_matches (hwaddr, hwaddrlen, nm_ip_addr_zero.addr_eth, sizeof (nm_ip_addr_zero.addr_eth))) {
_LOGD (LOGD_DEVICE, "device got a valid hw address");
nm_device_update_hw_address (self);
nm_device_update_initial_hw_address (self);
if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) {
/*
* If the device is UNAVAILABLE, any previous try to
* bring it up probably has failed because of the
* invalid hardware address; try again.
*/
nm_device_bring_up (self, TRUE, NULL);
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
}
}
}
} }
static gboolean static gboolean
@ -1663,9 +1622,6 @@ get_property (GObject *object, guint prop_id,
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
switch (prop_id) { switch (prop_id) {
case PROP_PERM_HW_ADDRESS:
g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (object)));
break;
case PROP_SPEED: case PROP_SPEED:
g_value_set_uint (value, priv->speed); g_value_set_uint (value, priv->speed);
break; break;
@ -1707,7 +1663,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
object_class->set_property = set_property; object_class->set_property = set_property;
parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->realize_start_notify = realize_start_notify;
parent_class->check_connection_compatible = check_connection_compatible; parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection; parent_class->complete_connection = complete_connection;
parent_class->new_default_connection = new_default_connection; parent_class->new_default_connection = new_default_connection;
@ -1726,13 +1681,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
parent_class->state_changed = device_state_changed; parent_class->state_changed = device_state_changed;
/* properties */ /* properties */
g_object_class_install_property
(object_class, PROP_PERM_HW_ADDRESS,
g_param_spec_string (NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property g_object_class_install_property
(object_class, PROP_SPEED, (object_class, PROP_SPEED,
g_param_spec_uint (NM_DEVICE_ETHERNET_SPEED, "", "", g_param_spec_uint (NM_DEVICE_ETHERNET_SPEED, "", "",

View file

@ -33,7 +33,6 @@ G_BEGIN_DECLS
#define NM_IS_DEVICE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_ETHERNET)) #define NM_IS_DEVICE_ETHERNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_ETHERNET))
#define NM_DEVICE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) #define NM_DEVICE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass))
#define NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS "perm-hw-address"
#define NM_DEVICE_ETHERNET_SPEED "speed" #define NM_DEVICE_ETHERNET_SPEED "speed"
#define NM_DEVICE_ETHERNET_S390_SUBCHANNELS "s390-subchannels" #define NM_DEVICE_ETHERNET_S390_SUBCHANNELS "s390-subchannels"

View file

@ -92,10 +92,10 @@ typedef struct {
* @connection: the #NMConnection to return the parent name for, if supported * @connection: the #NMConnection to return the parent name for, if supported
* *
* Given a connection, returns the a parent interface name, parent connection * Given a connection, returns the a parent interface name, parent connection
* UUID, or parent device hardware address for @connection. * UUID, or parent device permanent hardware address for @connection.
* *
* Returns: the parent interface name, parent connection UUID, parent * Returns: the parent interface name, parent connection UUID, parent
* device hardware address, or %NULL * device permenent hardware address, or %NULL
*/ */
const char * (*get_connection_parent) (NMDeviceFactory *factory, const char * (*get_connection_parent) (NMDeviceFactory *factory,
NMConnection *connection); NMConnection *connection);

View file

@ -147,11 +147,16 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (nm_device_is_real (device)) { if (nm_device_is_real (device)) {
const char *mac; const char *mac;
const char *hw_addr;
mac = nm_setting_infiniband_get_mac_address (s_infiniband); mac = nm_setting_infiniband_get_mac_address (s_infiniband);
if (mac && !nm_utils_hwaddr_matches (mac, -1, nm_device_get_hw_address (device), -1)) if (mac) {
hw_addr = nm_device_get_permanent_hw_address (device, TRUE);
if ( !hw_addr
|| !nm_utils_hwaddr_matches (mac, -1, hw_addr, -1))
return FALSE; return FALSE;
} }
}
return TRUE; return TRUE;
} }
@ -183,7 +188,7 @@ complete_connection (NMDevice *device,
} }
setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband); setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
hw_address = nm_device_get_hw_address (device); hw_address = nm_device_get_permanent_hw_address (device, TRUE);
if (setting_mac) { if (setting_mac) {
/* Make sure the setting MAC (if any) matches the device's MAC */ /* Make sure the setting MAC (if any) matches the device's MAC */
if (!nm_utils_hwaddr_matches (setting_mac, -1, hw_address, -1)) { if (!nm_utils_hwaddr_matches (setting_mac, -1, hw_address, -1)) {
@ -209,7 +214,7 @@ static void
update_connection (NMDevice *device, NMConnection *connection) update_connection (NMDevice *device, NMConnection *connection)
{ {
NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection); NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
const char *mac = nm_device_get_hw_address (device); const char *mac = nm_device_get_permanent_hw_address (device, TRUE);
const char *transport_mode = "datagram"; const char *transport_mode = "datagram";
int ifindex; int ifindex;

View file

@ -373,9 +373,8 @@ match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hw
if (!priv->parent) if (!priv->parent)
return !fail_if_no_hwaddr; return !fail_if_no_hwaddr;
parent_mac = nm_device_get_hw_address (priv->parent); parent_mac = nm_device_get_permanent_hw_address (priv->parent, FALSE);
return parent_mac && nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1);
return nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1);
} }
static gboolean static gboolean
@ -503,8 +502,6 @@ update_connection (NMDevice *device, NMConnection *connection)
static NMActStageReturn static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{ {
NMSettingWired *s_wired;
const char *cloned_mac;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -513,14 +510,9 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS) if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret; return ret;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED); if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE))
if (s_wired) { return NM_ACT_STAGE_RETURN_FAILURE;
/* Set device MAC address if the connection wants to change it */ return NM_ACT_STAGE_RETURN_SUCCESS;
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_HW);
}
return TRUE;
} }
static void static void
@ -549,16 +541,6 @@ realize_start_notify (NMDevice *device, const NMPlatformLink *plink)
update_properties (device); update_properties (device);
} }
static void
deactivate (NMDevice *device)
{
/* Reset MAC address back to initial address */
if (nm_device_get_initial_hw_address (device)) {
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device),
"reset", LOGD_DEVICE);
}
}
/******************************************************************/ /******************************************************************/
static void static void
@ -639,7 +621,6 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
device_class->complete_connection = complete_connection; device_class->complete_connection = complete_connection;
device_class->connection_type = NM_SETTING_MACVLAN_SETTING_NAME; device_class->connection_type = NM_SETTING_MACVLAN_SETTING_NAME;
device_class->create_and_realize = create_and_realize; device_class->create_and_realize = create_and_realize;
device_class->deactivate = deactivate;
device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_generic_capabilities = get_generic_capabilities;
device_class->ip4_config_pre_commit = ip4_config_pre_commit; device_class->ip4_config_pre_commit = ip4_config_pre_commit;
device_class->is_available = is_available; device_class->is_available = is_available;

View file

@ -56,8 +56,9 @@ gboolean nm_device_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmwar
void nm_device_take_down (NMDevice *self, gboolean block); void nm_device_take_down (NMDevice *self, gboolean block);
gboolean nm_device_set_hw_addr (NMDevice *device, const char *addr, gboolean nm_device_hw_addr_set (NMDevice *device, const char *addr, const char *detail);
const char *detail, guint64 hw_log_domain); gboolean nm_device_hw_addr_set_cloned (NMDevice *device, NMConnection *connection, gboolean is_wifi);
gboolean nm_device_hw_addr_reset (NMDevice *device, const char *detail);
void nm_device_set_firmware_missing (NMDevice *self, gboolean missing); void nm_device_set_firmware_missing (NMDevice *self, gboolean missing);
@ -107,6 +108,8 @@ void nm_device_queue_recheck_available (NMDevice *device,
void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config); void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config);
void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config); void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config);
gboolean nm_device_hw_addr_is_explict (NMDevice *device);
void nm_device_ip_method_failed (NMDevice *self, int family, NMDeviceStateReason reason); void nm_device_ip_method_failed (NMDevice *self, int family, NMDeviceStateReason reason);
gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value); gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value);

View file

@ -291,8 +291,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
{ {
NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTun *self = NM_DEVICE_TUN (device);
NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
NMSettingWired *s_wired;
const char *cloned_mac;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -305,12 +303,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
if (g_strcmp0 (priv->mode, "tap")) if (g_strcmp0 (priv->mode, "tap"))
return NM_ACT_STAGE_RETURN_SUCCESS; return NM_ACT_STAGE_RETURN_SUCCESS;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE))
if (s_wired) { return NM_ACT_STAGE_RETURN_FAILURE;
/* Set device MAC address if the connection wants to change it */
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE);
}
return NM_ACT_STAGE_RETURN_SUCCESS; return NM_ACT_STAGE_RETURN_SUCCESS;
} }

View file

@ -87,7 +87,6 @@ parent_hwaddr_maybe_changed (NMDevice *parent,
{ {
NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
NMConnection *connection; NMConnection *connection;
NMSettingWired *s_wired;
const char *new_mac, *old_mac; const char *new_mac, *old_mac;
NMSettingIPConfig *s_ip6; NMSettingIPConfig *s_ip6;
@ -100,11 +99,8 @@ parent_hwaddr_maybe_changed (NMDevice *parent,
return; return;
/* Update the VLAN MAC only if configuration does not specify one */ /* Update the VLAN MAC only if configuration does not specify one */
s_wired = nm_connection_get_setting_wired (connection); if (nm_device_hw_addr_is_explict (self))
if (s_wired) {
if (nm_setting_wired_get_cloned_mac_address (s_wired))
return; return;
}
old_mac = nm_device_get_hw_address (self); old_mac = nm_device_get_hw_address (self);
new_mac = nm_device_get_hw_address (parent); new_mac = nm_device_get_hw_address (parent);
@ -114,7 +110,7 @@ parent_hwaddr_maybe_changed (NMDevice *parent,
_LOGD (LOGD_VLAN, "parent hardware address changed to %s%s%s", _LOGD (LOGD_VLAN, "parent hardware address changed to %s%s%s",
NM_PRINT_FMT_QUOTE_STRING (new_mac)); NM_PRINT_FMT_QUOTE_STRING (new_mac));
if (new_mac) { if (new_mac) {
nm_device_set_hw_addr (self, new_mac, "set", LOGD_VLAN); nm_device_hw_addr_set (self, new_mac, "vlan-parent");
/* When changing the hw address the interface is taken down, /* When changing the hw address the interface is taken down,
* removing the IPv6 configuration; reapply it. * removing the IPv6 configuration; reapply it.
*/ */
@ -378,9 +374,10 @@ match_parent (NMDeviceVlan *self, const char *parent)
static gboolean static gboolean
match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hwaddr) match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hwaddr)
{ {
NMDeviceVlanPrivate *priv;
NMSettingWired *s_wired; NMSettingWired *s_wired;
const char *setting_mac; const char *setting_mac;
const char *device_mac; const char *parent_mac;
s_wired = nm_connection_get_setting_wired (connection); s_wired = nm_connection_get_setting_wired (connection);
if (!s_wired) if (!s_wired)
@ -390,9 +387,12 @@ match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hw
if (!setting_mac) if (!setting_mac)
return !fail_if_no_hwaddr; return !fail_if_no_hwaddr;
device_mac = nm_device_get_hw_address (device); priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
if (!priv->parent)
return !fail_if_no_hwaddr;
return nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1); parent_mac = nm_device_get_permanent_hw_address (priv->parent, FALSE);
return parent_mac && nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1);
} }
static gboolean static gboolean
@ -550,8 +550,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{ {
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (dev); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (dev);
NMSettingVlan *s_vlan; NMSettingVlan *s_vlan;
NMSettingWired *s_wired;
const char *cloned_mac;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -560,12 +558,8 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS) if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret; return ret;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (dev, NM_TYPE_SETTING_WIRED); if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE))
if (s_wired) { return NM_ACT_STAGE_RETURN_FAILURE;
/* Set device MAC address if the connection wants to change it */
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_VLAN);
}
/* Change MAC address to parent's one if needed */ /* Change MAC address to parent's one if needed */
if (priv->parent) if (priv->parent)
@ -619,14 +613,6 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
} }
} }
static void
deactivate (NMDevice *device)
{
/* Reset MAC address back to initial address */
if (nm_device_get_initial_hw_address (device))
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_VLAN);
}
/******************************************************************/ /******************************************************************/
static void static void
@ -690,7 +676,6 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->bring_up = bring_up; parent_class->bring_up = bring_up;
parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->act_stage1_prepare = act_stage1_prepare;
parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->ip4_config_pre_commit = ip4_config_pre_commit;
parent_class->deactivate = deactivate;
parent_class->is_available = is_available; parent_class->is_available = is_available;
parent_class->notify_new_device_added = notify_new_device_added; parent_class->notify_new_device_added = notify_new_device_added;

View file

@ -511,8 +511,6 @@ update_connection (NMDevice *device, NMConnection *connection)
static NMActStageReturn static NMActStageReturn
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
{ {
NMSettingWired *s_wired;
const char *cloned_mac;
NMActStageReturn ret; NMActStageReturn ret;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -521,12 +519,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS) if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret; return ret;
s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE))
if (s_wired) { return NM_ACT_STAGE_RETURN_FAILURE;
/* Set device MAC address if the connection wants to change it */
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE);
}
return NM_ACT_STAGE_RETURN_SUCCESS; return NM_ACT_STAGE_RETURN_SUCCESS;
} }

View file

@ -132,6 +132,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
PROP_IS_MASTER, PROP_IS_MASTER,
PROP_MASTER, PROP_MASTER,
PROP_HW_ADDRESS, PROP_HW_ADDRESS,
PROP_PERM_HW_ADDRESS,
PROP_HAS_PENDING_ACTION, PROP_HAS_PENDING_ACTION,
PROP_METERED, PROP_METERED,
PROP_LLDP_NEIGHBORS, PROP_LLDP_NEIGHBORS,
@ -208,6 +209,13 @@ typedef struct {
NMIP4Config **configs; NMIP4Config **configs;
} ArpingData; } ArpingData;
typedef enum {
HW_ADDR_TYPE_UNSET = 0,
HW_ADDR_TYPE_PERMANENT,
HW_ADDR_TYPE_EXPLICIT,
HW_ADDR_TYPE_GENERATED,
} HwAddrType;
typedef struct _NMDevicePrivate { typedef struct _NMDevicePrivate {
bool in_state_changed; bool in_state_changed;
@ -225,7 +233,12 @@ typedef struct _NMDevicePrivate {
char * udi; char * udi;
char * iface; /* may change, could be renamed by user */ char * iface; /* may change, could be renamed by user */
int ifindex; int ifindex;
guint hw_addr_len;
guint8 /*HwAddrType*/ hw_addr_type;
bool real; bool real;
char * ip_iface; char * ip_iface;
int ip_ifindex; int ip_ifindex;
NMDeviceType type; NMDeviceType type;
@ -237,13 +250,13 @@ typedef struct _NMDevicePrivate {
char * driver_version; char * driver_version;
char * firmware_version; char * firmware_version;
RfKillType rfkill_type; RfKillType rfkill_type;
bool firmware_missing; bool firmware_missing:1;
bool nm_plugin_missing; bool nm_plugin_missing:1;
bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */
GHashTable * available_connections; GHashTable * available_connections;
char * hw_addr; char * hw_addr;
guint hw_addr_len; char * hw_addr_perm;
char * perm_hw_addr; char * hw_addr_initial;
char * initial_hw_addr;
char * physical_port_id; char * physical_port_id;
guint dev_id; guint dev_id;
@ -616,6 +629,30 @@ _add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities)
/***********************************************************/ /***********************************************************/
static const char *
_get_stable_id (NMConnection *connection, NMUtilsStableType *out_stable_type)
{
NMSettingConnection *s_con;
const char *stable_id;
nm_assert (NM_IS_CONNECTION (connection));
nm_assert (out_stable_type);
s_con = nm_connection_get_setting_connection (connection);
g_return_val_if_fail (s_con, NULL);
stable_id = nm_setting_connection_get_stable_id (s_con);
if (!stable_id) {
*out_stable_type = NM_UTILS_STABLE_TYPE_UUID;
return nm_connection_get_uuid (connection);
}
*out_stable_type = NM_UTILS_STABLE_TYPE_STABLE_ID;
return stable_id;
}
/***********************************************************/
const char * const char *
nm_device_get_udi (NMDevice *self) nm_device_get_udi (NMDevice *self)
{ {
@ -1106,7 +1143,11 @@ nm_device_get_settings_connection (NMDevice *self)
NMConnection * NMConnection *
nm_device_get_applied_connection (NMDevice *self) nm_device_get_applied_connection (NMDevice *self)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
priv = NM_DEVICE_GET_PRIVATE (self);
return priv->act_request ? nm_act_request_get_applied_connection (priv->act_request) : NULL; return priv->act_request ? nm_act_request_get_applied_connection (priv->act_request) : NULL;
} }
@ -1123,23 +1164,12 @@ nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFla
} }
NMSetting * NMSetting *
nm_device_get_applied_setting (NMDevice *device, GType setting_type) nm_device_get_applied_setting (NMDevice *self, GType setting_type)
{ {
NMActRequest *req;
NMSetting *setting = NULL;
g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
req = nm_device_get_act_request (device);
if (req) {
NMConnection *connection; NMConnection *connection;
connection = nm_act_request_get_applied_connection (req); connection = nm_device_get_applied_connection (self);
if (connection) return connection ? nm_connection_get_setting (connection, setting_type) : NULL;
setting = nm_connection_get_setting (connection, setting_type);
}
return setting;
} }
RfKillType RfKillType
@ -1647,6 +1677,7 @@ device_link_changed (NMDevice *self)
int ifindex; int ifindex;
gboolean was_up; gboolean was_up;
gboolean update_unmanaged_specs = FALSE; gboolean update_unmanaged_specs = FALSE;
gboolean got_hw_addr = FALSE, had_hw_addr;
priv->device_link_changed_id = 0; priv->device_link_changed_id = 0;
@ -1684,6 +1715,11 @@ device_link_changed (NMDevice *self)
_notify (self, PROP_DRIVER); _notify (self, PROP_DRIVER);
} }
had_hw_addr = (priv->hw_addr != NULL);
nm_device_update_hw_address (self);
got_hw_addr = (!had_hw_addr && priv->hw_addr);
nm_device_update_permanent_hw_address (self);
if (info.name[0] && strcmp (priv->iface, info.name) != 0) { if (info.name[0] && strcmp (priv->iface, info.name) != 0) {
_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'", _LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
priv->ifindex, priv->iface, info.name); priv->ifindex, priv->iface, info.name);
@ -1775,6 +1811,20 @@ device_link_changed (NMDevice *self)
if (update_unmanaged_specs) if (update_unmanaged_specs)
nm_device_set_unmanaged_by_user_settings (self, nm_settings_get_unmanaged_specs (priv->settings)); nm_device_set_unmanaged_by_user_settings (self, nm_settings_get_unmanaged_specs (priv->settings));
if ( got_hw_addr
&& !priv->up
&& nm_device_get_state (self) == NM_DEVICE_STATE_UNAVAILABLE) {
/*
* If the device is UNAVAILABLE, any previous try to
* bring it up probably has failed because of the
* invalid hardware address; try again.
*/
nm_device_bring_up (self, TRUE, NULL);
nm_device_queue_recheck_available (self,
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
}
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@ -2123,6 +2173,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink)
nm_device_update_hw_address (self); nm_device_update_hw_address (self);
nm_device_update_initial_hw_address (self); nm_device_update_initial_hw_address (self);
nm_device_update_permanent_hw_address (self);
/* Note: initial hardware address must be read before calling get_ignore_carrier() */ /* Note: initial hardware address must be read before calling get_ignore_carrier() */
config = nm_config_get (); config = nm_config_get ();
@ -2308,6 +2359,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
_notify (self, PROP_UDI); _notify (self, PROP_UDI);
} }
if (priv->hw_addr) { if (priv->hw_addr) {
priv->hw_addr_len = 0;
g_clear_pointer (&priv->hw_addr, g_free); g_clear_pointer (&priv->hw_addr, g_free);
_notify (self, PROP_HW_ADDRESS); _notify (self, PROP_HW_ADDRESS);
} }
@ -2316,8 +2368,10 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error)
_notify (self, PROP_PHYSICAL_PORT_ID); _notify (self, PROP_PHYSICAL_PORT_ID);
} }
g_clear_pointer (&priv->perm_hw_addr, g_free); priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
g_clear_pointer (&priv->initial_hw_addr, g_free); g_clear_pointer (&priv->hw_addr_perm, g_free);
_notify (self, PROP_PERM_HW_ADDRESS);
g_clear_pointer (&priv->hw_addr_initial, g_free);
priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities)
@ -3324,7 +3378,7 @@ nm_device_can_assume_connections (NMDevice *self)
* if there is no active connection or the active connection cannot be * if there is no active connection or the active connection cannot be
* assumed. * assumed.
*/ */
gboolean static gboolean
nm_device_can_assume_active_connection (NMDevice *self) nm_device_can_assume_active_connection (NMDevice *self)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@ -3371,6 +3425,45 @@ nm_device_can_assume_active_connection (NMDevice *self)
return TRUE; return TRUE;
} }
static gboolean
unmanaged_on_quit (NMDevice *self)
{
/* Leave certain devices alone when quitting so their configuration
* can be taken over when NM restarts. This ensures connectivity while
* NM is stopped.
*/
if (nm_device_uses_assumed_connection (self)) {
/* An assume connection must be left alone */
return FALSE;
}
if (!nm_device_get_act_request (self)) {
/* a device without any active connection is either UNAVAILABLE or DISCONNECTED
* state. Since we don't know whether the device was upped by NetworkManager,
* we must leave it up on exit.
*/
return FALSE;
}
if (!nm_platform_link_can_assume (NM_PLATFORM_GET, nm_device_get_ifindex (self))) {
/* The device has no layer 3 configuration. Leave it up. */
return FALSE;
}
if (nm_device_can_assume_active_connection (self))
return FALSE;
return TRUE;
}
gboolean
nm_device_unmanage_on_quit (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
return NM_DEVICE_GET_CLASS (self)->unmanaged_on_quit (self);
}
static gboolean static gboolean
nm_device_emit_recheck_assume (gpointer user_data) nm_device_emit_recheck_assume (gpointer user_data)
{ {
@ -5859,9 +5952,15 @@ check_and_add_ipv6ll_addr (NMDevice *self)
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
if (!nm_utils_ipv6_addr_set_stable_privacy (&lladdr, NMUtilsStableType stable_type;
const char *stable_id;
stable_id = _get_stable_id (connection, &stable_type);
if ( !stable_id
|| !nm_utils_ipv6_addr_set_stable_privacy (stable_type,
&lladdr,
nm_device_get_iface (self), nm_device_get_iface (self),
nm_connection_get_uuid (connection), stable_id,
priv->linklocal6_dad_counter++, priv->linklocal6_dad_counter++,
&error)) { &error)) {
_LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message); _LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message);
@ -6205,6 +6304,8 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
NMActStageReturn ret; NMActStageReturn ret;
NMSettingIP6Config *s_ip6 = NULL; NMSettingIP6Config *s_ip6 = NULL;
GError *error = NULL; GError *error = NULL;
NMUtilsStableType stable_type;
const char *stable_id;
connection = nm_device_get_applied_connection (self); connection = nm_device_get_applied_connection (self);
g_assert (connection); g_assert (connection);
@ -6218,12 +6319,16 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
g_assert (s_ip6); g_assert (s_ip6);
stable_id = _get_stable_id (connection, &stable_type);
if (stable_id) {
priv->rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, priv->rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET,
nm_device_get_ip_ifindex (self), nm_device_get_ip_ifindex (self),
nm_device_get_ip_iface (self), nm_device_get_ip_iface (self),
nm_connection_get_uuid (connection), stable_type,
stable_id,
nm_setting_ip6_config_get_addr_gen_mode (s_ip6), nm_setting_ip6_config_get_addr_gen_mode (s_ip6),
&error); &error);
}
if (!priv->rdisc) { if (!priv->rdisc) {
_LOGE (LOGD_IP6, "addrconf6: failed to start router discovery: %s", error->message); _LOGE (LOGD_IP6, "addrconf6: failed to start router discovery: %s", error->message);
g_error_free (error); g_error_free (error);
@ -10548,6 +10653,8 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0");
} }
nm_device_hw_addr_reset (self, "deactivate");
/* Call device type-specific deactivation */ /* Call device type-specific deactivation */
if (NM_DEVICE_GET_CLASS (self)->deactivate) if (NM_DEVICE_GET_CLASS (self)->deactivate)
NM_DEVICE_GET_CLASS (self)->deactivate (self); NM_DEVICE_GET_CLASS (self)->deactivate (self);
@ -10622,6 +10729,8 @@ nm_device_spawn_iface_helper (NMDevice *self)
GPtrArray *argv; GPtrArray *argv;
gs_free char *dhcp4_address = NULL; gs_free char *dhcp4_address = NULL;
char *logging_backend; char *logging_backend;
NMUtilsStableType stable_type;
const char *stable_id;
if (priv->state != NM_DEVICE_STATE_ACTIVATED) if (priv->state != NM_DEVICE_STATE_ACTIVATED)
return; return;
@ -10640,6 +10749,12 @@ nm_device_spawn_iface_helper (NMDevice *self)
g_ptr_array_add (argv, g_strdup ("--uuid")); g_ptr_array_add (argv, g_strdup ("--uuid"));
g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection))); g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection)));
stable_id = _get_stable_id (connection, &stable_type);
if (stable_id && stable_type != NM_UTILS_STABLE_TYPE_UUID) {
g_ptr_array_add (argv, g_strdup ("--stable-id"));
g_ptr_array_add (argv, g_strdup_printf ("%d %s", (int) stable_type, stable_id));
}
logging_backend = nm_config_get_is_debug (nm_config_get ()) logging_backend = nm_config_get_is_debug (nm_config_get ())
? g_strdup ("debug") ? g_strdup ("debug")
: nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG, : nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
@ -10935,6 +11050,7 @@ _set_state_full (NMDevice *self,
if (nm_device_get_act_request (self)) if (nm_device_get_act_request (self))
nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE);
nm_device_take_down (self, TRUE); nm_device_take_down (self, TRUE);
nm_device_hw_addr_reset (self, "unmanage");
set_nm_ipv6ll (self, FALSE); set_nm_ipv6ll (self, FALSE);
restore_ip6_properties (self); restore_ip6_properties (self);
} }
@ -10982,6 +11098,9 @@ _set_state_full (NMDevice *self,
} }
} }
break; break;
case NM_DEVICE_STATE_PREPARE:
nm_device_update_initial_hw_address (self);
break;
case NM_DEVICE_STATE_NEED_AUTH: case NM_DEVICE_STATE_NEED_AUTH:
if (old_state > NM_DEVICE_STATE_NEED_AUTH) { if (old_state > NM_DEVICE_STATE_NEED_AUTH) {
/* Clean up any half-done IP operations if the device's layer2 /* Clean up any half-done IP operations if the device's layer2
@ -11300,23 +11419,26 @@ nm_device_get_hw_address (NMDevice *self)
g_return_val_if_fail (NM_IS_DEVICE (self), NULL); g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
priv = NM_DEVICE_GET_PRIVATE (self); priv = NM_DEVICE_GET_PRIVATE (self);
return priv->hw_addr_len ? priv->hw_addr : NULL; nm_assert ((!priv->hw_addr) ^ (priv->hw_addr_len > 0));
return priv->hw_addr;
} }
void void
nm_device_update_hw_address (NMDevice *self) nm_device_update_hw_address (NMDevice *self)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv;
int ifindex = nm_device_get_ifindex (self);
const guint8 *hwaddr; const guint8 *hwaddr;
gsize hwaddrlen = 0; gsize hwaddrlen = 0;
if (ifindex <= 0) priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->ifindex <= 0)
return; return;
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen); hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &hwaddrlen);
if ( priv->type == NM_DEVICE_TYPE_ETHERNET if ( priv->type == NM_DEVICE_TYPE_ETHERNET
&& hwaddr
&& nm_utils_hwaddr_matches (hwaddr, hwaddrlen, nm_ip_addr_zero.addr_eth, sizeof (nm_ip_addr_zero.addr_eth))) && nm_utils_hwaddr_matches (hwaddr, hwaddrlen, nm_ip_addr_zero.addr_eth, sizeof (nm_ip_addr_zero.addr_eth)))
hwaddrlen = 0; hwaddrlen = 0;
@ -11326,17 +11448,28 @@ nm_device_update_hw_address (NMDevice *self)
g_free (priv->hw_addr); g_free (priv->hw_addr);
priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen); priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen);
_LOGD (LOGD_HW | LOGD_DEVICE, "hardware address now %s", priv->hw_addr); _LOGD (LOGD_HW | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr);
_notify (self, PROP_HW_ADDRESS); _notify (self, PROP_HW_ADDRESS);
if ( !priv->hw_addr_initial
|| ( priv->hw_addr_type == HW_ADDR_TYPE_UNSET
&& priv->state < NM_DEVICE_STATE_PREPARE
&& !nm_device_is_activating (self))) {
/* when we get a hw_addr the first time or while the device
* is not activated (with no explict hw address set), always
* update our inital hw-address as well. */
nm_device_update_initial_hw_address (self);
}
} }
} else { } else {
/* Invalid or no hardware address */ /* Invalid or no hardware address */
if (priv->hw_addr_len != 0) { if (priv->hw_addr_len != 0) {
g_clear_pointer (&priv->hw_addr, g_free);
priv->hw_addr_len = 0;
_LOGD (LOGD_HW | LOGD_DEVICE, _LOGD (LOGD_HW | LOGD_DEVICE,
"previous hardware address is no longer valid"); "hw-addr: failed reading current MAC address (stay with %s)",
_notify (self, PROP_HW_ADDRESS); priv->hw_addr);
} else {
_LOGD (LOGD_HW | LOGD_DEVICE,
"hw-addr: failed reading current MAC address");
} }
} }
} }
@ -11346,84 +11479,361 @@ nm_device_update_initial_hw_address (NMDevice *self)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->hw_addr_len) { if ( priv->hw_addr
priv->initial_hw_addr = g_strdup (priv->hw_addr); && !nm_streq0 (priv->hw_addr_initial, priv->hw_addr)) {
_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr); if ( priv->hw_addr_initial
&& priv->hw_addr_type != HW_ADDR_TYPE_UNSET) {
/* once we have the initial hw address set, we only allow
* update if the currenty type is "unset". */
return;
}
g_free (priv->hw_addr_initial);
priv->hw_addr_initial = g_strdup (priv->hw_addr);
_LOGD (LOGD_DEVICE, "hw-addr: update initial MAC address %s",
priv->hw_addr_initial);
}
}
if (priv->ifindex > 0) { void
nm_device_update_permanent_hw_address (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
size_t len = 0; size_t len = 0;
gboolean success_read;
if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) { if (priv->hw_addr_perm) {
g_warn_if_fail (len == priv->hw_addr_len); /* the permanent hardware address is only read once and not
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); * re-read later.
_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s", *
priv->perm_hw_addr); * Except during unrealize/realize cycles, where we clear the permanent
* hardware address during unrealization. */
return;
}
if (priv->ifindex <= 0)
return;
if (!priv->hw_addr_len) {
nm_device_update_hw_address (self);
if (!priv->hw_addr_len)
return;
}
success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len);
if (!success_read || len != priv->hw_addr_len) {
/* Fall back to current address. We use the fake address and keep it
* until the device unrealizes.
*
* In some cases it might be necessary to know whether this is a "real" or
* a temporary address (fake). */
_LOGD (LOGD_HW | LOGD_ETHER, "hw-addr: %s (use current: %s)",
success_read
? "unable to read permanent MAC address"
: "read HW addr length of permanent MAC address differs",
priv->hw_addr);
priv->hw_addr_perm_fake = TRUE;
priv->hw_addr_perm = g_strdup (priv->hw_addr);
} else { } else {
/* Fall back to current address */ priv->hw_addr_perm_fake = FALSE;
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address"); priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, len);
priv->perm_hw_addr = g_strdup (priv->hw_addr); _LOGD (LOGD_DEVICE, "hw-addr: read permanent MAC address '%s'",
priv->hw_addr_perm);
} }
_notify (self, PROP_PERM_HW_ADDRESS);
} }
static const char *
_get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr)
{
NMSetting *setting;
const char *addr = NULL;
nm_assert (out_addr && !*out_addr);
setting = nm_connection_get_setting (connection,
is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED);
if (setting) {
addr = is_wifi
? nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) setting)
: nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) setting);
} }
if (!addr) {
gs_free char *a = NULL;
a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
is_wifi ? "wifi.cloned-mac-address" : "ethernet.cloned-mac-address",
self);
/* default is permanent. */
addr = NM_CLONED_MAC_PERMANENT;
if (!a) {
if (is_wifi) {
NMSettingMacRandomization v;
/* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */
a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"wifi." NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION,
self);
v = _nm_utils_ascii_str_to_int64 (a, 10,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
NM_SETTING_MAC_RANDOMIZATION_ALWAYS,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT);
if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS)
addr = NM_CLONED_MAC_RANDOM;
}
} else if ( NM_CLONED_MAC_IS_SPECIAL (a)
|| nm_utils_hwaddr_valid (a, ETH_ALEN))
addr = *out_addr = g_steal_pointer (&a);
}
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 gboolean
nm_device_set_hw_addr (NMDevice *self, const char *addr, nm_device_hw_addr_is_explict (NMDevice *self)
const char *detail, guint64 hw_log_domain)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv;
gboolean success = FALSE;
const char *cur_addr = nm_device_get_hw_address (self);
guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
/* Fall back to the permanent address */ g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
if (!addr)
addr = priv->perm_hw_addr; priv = NM_DEVICE_GET_PRIVATE (self);
if (!addr) return !NM_IN_SET (priv->hw_addr_type, HW_ADDR_TYPE_PERMANENT, HW_ADDR_TYPE_UNSET);
return FALSE; }
static gboolean
_hw_addr_set (NMDevice *self,
const char *addr,
const char *operation,
const char *detail)
{
NMDevicePrivate *priv;
gboolean success = FALSE;
const char *cur_addr;
guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX];
guint hw_addr_len;
gboolean was_up;
nm_assert (NM_IS_DEVICE (self));
nm_assert (addr);
nm_assert (operation);
priv = NM_DEVICE_GET_PRIVATE (self);
cur_addr = nm_device_get_hw_address (self);
/* Do nothing if current MAC is same */ /* Do nothing if current MAC is same */
if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) { if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
_LOGD (LOGD_DEVICE | hw_log_domain, "no MAC address change needed"); _LOGD (LOGD_DEVICE, "set-hw-addr: no MAC address change needed");
return TRUE; return TRUE;
} }
if (!nm_utils_hwaddr_aton (addr, addr_bytes, priv->hw_addr_len)) {
_LOGW (LOGD_DEVICE | hw_log_domain, "invalid MAC address %s", addr);
return FALSE;
}
hw_addr_len = priv->hw_addr_len;
if (!hw_addr_len)
hw_addr_len = _nm_utils_hwaddr_length (addr);
if ( !hw_addr_len
|| !nm_utils_hwaddr_aton (addr, addr_bytes, hw_addr_len))
g_return_val_if_reached (FALSE);
_LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s' (%s, %s)...", addr, operation, detail);
was_up = nm_device_is_up (self);
if (was_up) {
/* Can't change MAC address while device is up */ /* Can't change MAC address while device is up */
nm_device_take_down (self, FALSE); nm_device_take_down (self, FALSE);
}
success = nm_platform_link_set_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), addr_bytes, priv->hw_addr_len); success = nm_platform_link_set_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), addr_bytes, hw_addr_len);
if (success) { if (success) {
/* MAC address succesfully changed; update the current MAC to match */ /* MAC address succesfully changed; update the current MAC to match */
nm_device_update_hw_address (self); nm_device_update_hw_address (self);
cur_addr = nm_device_get_hw_address (self); cur_addr = nm_device_get_hw_address (self);
if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) { if (cur_addr && nm_utils_hwaddr_matches (cur_addr, -1, addr, -1)) {
_LOGI (LOGD_DEVICE | hw_log_domain, "%s MAC address to %s", _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)",
detail, addr); operation, addr, detail);
} else { } else {
_LOGW (LOGD_DEVICE | hw_log_domain, _LOGW (LOGD_DEVICE,
"new MAC address %s not successfully set", addr); "set-hw-addr: new MAC address %s not successfully set to %s (%s)",
addr, operation, detail);
success = FALSE; success = FALSE;
} }
} else { } else {
_LOGW (LOGD_DEVICE | hw_log_domain, "failed to %s MAC address to %s", _LOGW (LOGD_DEVICE, "set-hw-addr: failed to %s MAC address to %s (%s)",
detail, addr); operation, addr, detail);
}
if (was_up) {
if (!nm_device_bring_up (self, TRUE, NULL))
return FALSE;
} }
nm_device_bring_up (self, TRUE, NULL);
return success; return success;
} }
const char * gboolean
nm_device_get_permanent_hw_address (NMDevice *self) nm_device_hw_addr_set (NMDevice *self, const char *addr, const char *detail)
{ {
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
if (!addr)
g_return_val_if_reached (FALSE);
/* this is called by NMDeviceVlan to take the MAC address from the parent
* and by NMDeviceWifi to set a random MAC address during scanning.
* In this case, it's like setting it to PERMANENT. */
priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT;
return _hw_addr_set (self, addr, "set", detail);
}
gboolean
nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi)
{
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);
priv = NM_DEVICE_GET_PRIVATE (self);
if (!connection)
g_return_val_if_reached (FALSE);
addr = addr_setting = _get_cloned_mac_address_setting (self, connection, is_wifi, &hw_addr_tmp);
if (nm_streq (addr, NM_CLONED_MAC_PRESERVE)) {
/* "preserve" means to reset the initial MAC address. */
return nm_device_hw_addr_reset (self, addr_setting);
}
if (nm_streq (addr, NM_CLONED_MAC_PERMANENT)) {
addr = nm_device_get_permanent_hw_address (self, TRUE);
if (!addr)
return FALSE;
priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT;
} else if (NM_IN_STRSET (addr, NM_CLONED_MAC_RANDOM)) {
if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) {
/* hm, we already use a generate MAC address. Most certainly, that is from the same
* activation request, so we should not create a new random address, instead keep
* the current. */
return TRUE;
}
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;
}
priv->hw_addr_type = HW_ADDR_TYPE_GENERATED;
addr = hw_addr_generated;
} else if (NM_IN_STRSET (addr, NM_CLONED_MAC_STABLE)) {
NMUtilsStableType stable_type;
const char *stable_id;
if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) {
/* hm, we already use a generate MAC address. Most certainly, that is from the same
* activation request, so let's skip creating the stable address anew. */
return TRUE;
}
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_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");
return FALSE;
}
priv->hw_addr_type = HW_ADDR_TYPE_GENERATED;
addr = hw_addr_generated;
} else {
/* this must be a valid address. Otherwise, we shouldn't come here. */
if (_nm_utils_hwaddr_length (addr) <= 0) {
g_return_val_if_reached (FALSE);
}
priv->hw_addr_type = HW_ADDR_TYPE_EXPLICIT;
}
return _hw_addr_set (self, addr, "set-cloned", addr_setting);
}
gboolean
nm_device_hw_addr_reset (NMDevice *self, const char *detail)
{
NMDevicePrivate *priv;
const char *addr;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->hw_addr_type == HW_ADDR_TYPE_UNSET)
return TRUE;
priv->hw_addr_type = HW_ADDR_TYPE_UNSET;
addr = nm_device_get_initial_hw_address (self);
if (!addr) {
/* as hw_addr_type is not UNSET, we expect that we can get an
* initial address to which to reset. */
g_return_val_if_reached (FALSE);
}
return _hw_addr_set (self, addr, "reset", detail);
}
const char *
nm_device_get_permanent_hw_address (NMDevice *self, gboolean fallback_fake)
{
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL); g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->perm_hw_addr; priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->hw_addr_perm)
return NULL;
if ( priv->hw_addr_perm_fake
&& !fallback_fake)
return NULL;
return priv->hw_addr_perm;
} }
const char * const char *
@ -11431,7 +11841,7 @@ nm_device_get_initial_hw_address (NMDevice *self)
{ {
g_return_val_if_fail (NM_IS_DEVICE (self), NULL); g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->initial_hw_addr; return NM_DEVICE_GET_PRIVATE (self)->hw_addr_initial;
} }
/** /**
@ -11469,9 +11879,9 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs)
static NMMatchSpecMatchType static NMMatchSpecMatchType
spec_match_list (NMDevice *self, const GSList *specs) spec_match_list (NMDevice *self, const GSList *specs)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m; NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m;
const GSList *iter; const GSList *iter;
const char *hw_addr_perm;
for (iter = specs; iter; iter = g_slist_next (iter)) { for (iter = specs; iter; iter = g_slist_next (iter)) {
if (!strcmp ((const char *) iter->data, "*")) { if (!strcmp ((const char *) iter->data, "*")) {
@ -11479,8 +11889,10 @@ spec_match_list (NMDevice *self, const GSList *specs)
break; break;
} }
} }
if (priv->hw_addr_len && priv->hw_addr) {
m = nm_match_spec_hwaddr (specs, priv->hw_addr); hw_addr_perm = nm_device_get_permanent_hw_address (self, FALSE);
if (hw_addr_perm) {
m = nm_match_spec_hwaddr (specs, hw_addr_perm);
matched = MAX (matched, m); matched = MAX (matched, m);
} }
if (matched != NM_MATCH_SPEC_NEG_MATCH) { if (matched != NM_MATCH_SPEC_NEG_MATCH) {
@ -11563,7 +11975,8 @@ constructor (GType type,
self = NM_DEVICE (object); self = NM_DEVICE (object);
priv = NM_DEVICE_GET_PRIVATE (self); priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->iface) { if ( priv->iface
&& G_LIKELY (!nm_utils_get_testing ())) {
pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface); pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface);
if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) { if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) {
@ -11572,6 +11985,17 @@ constructor (GType type,
} }
} }
if (priv->hw_addr_perm) {
priv->hw_addr_len = _nm_utils_hwaddr_length (priv->hw_addr_perm);
if (!priv->hw_addr_len) {
g_clear_pointer (&priv->hw_addr_perm, g_free);
g_return_val_if_reached (object);
}
priv->hw_addr = g_strdup (priv->hw_addr_perm);
_LOGT (LOGD_DEVICE, "hw-addr: has permanent hw-address '%s'", priv->hw_addr_perm);
}
return object; return object;
} }
@ -11697,8 +12121,8 @@ finalize (GObject *object)
_LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self)); _LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self));
g_free (priv->hw_addr); g_free (priv->hw_addr);
g_free (priv->perm_hw_addr); g_free (priv->hw_addr_perm);
g_free (priv->initial_hw_addr); g_free (priv->hw_addr_initial);
g_slist_free_full (priv->pending_actions, g_free); g_slist_free_full (priv->pending_actions, g_free);
g_slist_free_full (priv->dad6_failed_addrs, g_free); g_slist_free_full (priv->dad6_failed_addrs, g_free);
g_clear_pointer (&priv->physical_port_id, g_free); g_clear_pointer (&priv->physical_port_id, g_free);
@ -11727,10 +12151,8 @@ static void
set_property (GObject *object, guint prop_id, set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec) const GValue *value, GParamSpec *pspec)
{ {
NMDevice *self = NM_DEVICE (object); NMDevice *self = (NMDevice *) object;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *hw_addr, *p;
guint count;
switch (prop_id) { switch (prop_id) {
case PROP_UDI: case PROP_UDI:
@ -11808,32 +12230,9 @@ set_property (GObject *object, guint prop_id,
case PROP_IS_MASTER: case PROP_IS_MASTER:
priv->is_master = g_value_get_boolean (value); priv->is_master = g_value_get_boolean (value);
break; break;
case PROP_HW_ADDRESS: case PROP_PERM_HW_ADDRESS:
/* construct only */ /* construct only */
p = hw_addr = g_value_get_string (value); priv->hw_addr_perm = g_value_dup_string (value);
/* Hardware address length is the number of ':' plus 1 */
count = 1;
while (p && *p) {
if (*p++ == ':')
count++;
}
if (count < ETH_ALEN || count > NM_UTILS_HWADDR_LEN_MAX) {
if (hw_addr && *hw_addr) {
_LOGW (LOGD_DEVICE, "ignoring hardware address '%s' with unexpected length %d",
hw_addr, count);
}
break;
}
priv->hw_addr_len = count;
g_free (priv->hw_addr);
if (nm_utils_hwaddr_valid (hw_addr, priv->hw_addr_len))
priv->hw_addr = g_strdup (hw_addr);
else {
_LOGW (LOGD_DEVICE, "could not parse hw-address '%s'", hw_addr);
priv->hw_addr = NULL;
}
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -11956,6 +12355,10 @@ get_property (GObject *object, guint prop_id,
case PROP_HW_ADDRESS: case PROP_HW_ADDRESS:
g_value_set_string (value, priv->hw_addr); g_value_set_string (value, priv->hw_addr);
break; break;
case PROP_PERM_HW_ADDRESS:
/* this property is exposed on D-Bus for NMDeviceEthernet and NMDeviceWifi. */
g_value_set_string (value, nm_device_get_permanent_hw_address (self, FALSE));
break;
case PROP_HAS_PENDING_ACTION: case PROP_HAS_PENDING_ACTION:
g_value_set_boolean (value, nm_device_has_pending_action (self)); g_value_set_boolean (value, nm_device_has_pending_action (self));
break; break;
@ -12041,6 +12444,7 @@ nm_device_class_init (NMDeviceClass *klass)
klass->take_down = take_down; klass->take_down = take_down;
klass->carrier_changed = carrier_changed; klass->carrier_changed = carrier_changed;
klass->get_ip_iface_identifier = get_ip_iface_identifier; klass->get_ip_iface_identifier = get_ip_iface_identifier;
klass->unmanaged_on_quit = unmanaged_on_quit;
/* Properties */ /* Properties */
obj_properties[PROP_UDI] = obj_properties[PROP_UDI] =
@ -12198,6 +12602,11 @@ nm_device_class_init (NMDeviceClass *klass)
G_PARAM_STATIC_STRINGS); G_PARAM_STATIC_STRINGS);
obj_properties[PROP_HW_ADDRESS] = obj_properties[PROP_HW_ADDRESS] =
g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "", g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_PERM_HW_ADDRESS] =
g_param_spec_string (NM_DEVICE_PERM_HW_ADDRESS, "", "",
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS); G_PARAM_STATIC_STRINGS);

View file

@ -57,6 +57,11 @@
#define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id" #define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id"
#define NM_DEVICE_MTU "mtu" #define NM_DEVICE_MTU "mtu"
#define NM_DEVICE_HW_ADDRESS "hw-address" #define NM_DEVICE_HW_ADDRESS "hw-address"
/* "perm-hw-address" is exposed on D-Bus both for NMDeviceEthernet
* and NMDeviceWifi. */
#define NM_DEVICE_PERM_HW_ADDRESS "perm-hw-address"
#define NM_DEVICE_METERED "metered" #define NM_DEVICE_METERED "metered"
#define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors" #define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors"
#define NM_DEVICE_REAL "real" #define NM_DEVICE_REAL "real"
@ -323,6 +328,8 @@ typedef struct {
gboolean (* owns_iface) (NMDevice *self, const char *iface); gboolean (* owns_iface) (NMDevice *self, const char *iface);
NMConnection * (* new_default_connection) (NMDevice *self); NMConnection * (* new_default_connection) (NMDevice *self);
gboolean (* unmanaged_on_quit) (NMDevice *self);
} NMDeviceClass; } NMDeviceClass;
typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device, typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
@ -353,7 +360,8 @@ guint32 nm_device_get_ip4_route_metric (NMDevice *dev);
guint32 nm_device_get_ip6_route_metric (NMDevice *dev); guint32 nm_device_get_ip6_route_metric (NMDevice *dev);
const char * nm_device_get_hw_address (NMDevice *dev); const char * nm_device_get_hw_address (NMDevice *dev);
const char * nm_device_get_permanent_hw_address (NMDevice *dev); const char * nm_device_get_permanent_hw_address (NMDevice *dev,
gboolean fallback_fake);
const char * nm_device_get_initial_hw_address (NMDevice *dev); const char * nm_device_get_initial_hw_address (NMDevice *dev);
NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev);
@ -411,7 +419,7 @@ gboolean nm_device_check_slave_connection_compatible (NMDevice *device, NMConnec
gboolean nm_device_uses_assumed_connection (NMDevice *device); gboolean nm_device_uses_assumed_connection (NMDevice *device);
gboolean nm_device_can_assume_active_connection (NMDevice *device); gboolean nm_device_unmanage_on_quit (NMDevice *self);
gboolean nm_device_spec_match_list (NMDevice *device, const GSList *specs); gboolean nm_device_spec_match_list (NMDevice *device, const GSList *specs);
@ -578,6 +586,7 @@ void nm_device_reactivate_ip6_config (NMDevice *device,
void nm_device_update_hw_address (NMDevice *self); void nm_device_update_hw_address (NMDevice *self);
void nm_device_update_initial_hw_address (NMDevice *self); void nm_device_update_initial_hw_address (NMDevice *self);
void nm_device_update_permanent_hw_address (NMDevice *self);
void nm_device_update_dynamic_ip_setup (NMDevice *self); void nm_device_update_dynamic_ip_setup (NMDevice *self);
G_END_DECLS G_END_DECLS

View file

@ -62,6 +62,8 @@ _LOG_DECLARE_SELF(NMDeviceWifi);
#define SCAN_INTERVAL_STEP 20 #define SCAN_INTERVAL_STEP 20
#define SCAN_INTERVAL_MAX 120 #define SCAN_INTERVAL_MAX 120
#define SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN 5
#define WIRELESS_SECRETS_TRIES "wireless-secrets-tries" #define WIRELESS_SECRETS_TRIES "wireless-secrets-tries"
G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE) G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
@ -71,7 +73,6 @@ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
enum { enum {
PROP_0, PROP_0,
PROP_PERM_HW_ADDRESS,
PROP_MODE, PROP_MODE,
PROP_BITRATE, PROP_BITRATE,
PROP_ACCESS_POINTS, PROP_ACCESS_POINTS,
@ -120,6 +121,9 @@ struct _NMDeviceWifiPrivate {
guint reacquire_iface_id; guint reacquire_iface_id;
NMDeviceWifiCapabilities capabilities; NMDeviceWifiCapabilities capabilities;
gint32 hw_addr_scan_expire;
char *hw_addr_scan;
}; };
static gboolean check_scanning_allowed (NMDeviceWifi *self); static gboolean check_scanning_allowed (NMDeviceWifi *self);
@ -170,6 +174,8 @@ static void ap_add_remove (NMDeviceWifi *self,
static void remove_supplicant_interface_error_handler (NMDeviceWifi *self); static void remove_supplicant_interface_error_handler (NMDeviceWifi *self);
static void _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset);
/*****************************************************************/ /*****************************************************************/
static void static void
@ -187,6 +193,18 @@ constructed (GObject *object)
priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ()); priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ());
} }
static gboolean
unmanaged_on_quit (NMDevice *self)
{
/* Wi-Fi devices cannot be assumed and are always taken down.
* However, also when being disconnected, we scan and thus
* set the MAC address to a random value.
*
* We must restore the original MAC address when quitting, thus
* signal to unmanage the device. */
return TRUE;
}
static gboolean static gboolean
supplicant_interface_acquire (NMDeviceWifi *self) supplicant_interface_acquire (NMDeviceWifi *self)
{ {
@ -403,14 +421,6 @@ periodic_update_cb (gpointer user_data)
return TRUE; return TRUE;
} }
static void
realize_start_notify (NMDevice *device, const NMPlatformLink *plink)
{
NM_DEVICE_CLASS (nm_device_wifi_parent_class)->realize_start_notify (device, plink);
g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS);
}
static gboolean static gboolean
bring_up (NMDevice *device, gboolean *no_firmware) bring_up (NMDevice *device, gboolean *no_firmware)
{ {
@ -491,9 +501,8 @@ deactivate (NMDevice *device)
/* Clear any critical protocol notification in the Wi-Fi stack */ /* Clear any critical protocol notification in the Wi-Fi stack */
nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE);
/* Reset MAC address back to initial address */ g_clear_pointer (&priv->hw_addr_scan, g_free);
if (nm_device_get_initial_hw_address (device)) _hw_addr_set_scanning (self, TRUE);
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI);
/* Ensure we're in infrastructure mode after deactivation; some devices /* Ensure we're in infrastructure mode after deactivation; some devices
* (usually older ones) don't scan well in adhoc mode. * (usually older ones) don't scan well in adhoc mode.
@ -572,7 +581,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_wireless) if (!s_wireless)
return FALSE; return FALSE;
perm_hw_addr = nm_device_get_permanent_hw_address (device); perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
mac = nm_setting_wireless_get_mac_address (s_wireless); mac = nm_setting_wireless_get_mac_address (s_wireless);
if (perm_hw_addr) { if (perm_hw_addr) {
if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1))
@ -685,14 +694,17 @@ check_connection_available (NMDevice *device,
return !!find_first_compatible_ap (NM_DEVICE_WIFI (device), connection, TRUE); return !!find_first_compatible_ap (NM_DEVICE_WIFI (device), connection, TRUE);
} }
static gboolean
is_manf_default_ssid (const GByteArray *ssid)
{
int i;
/* /*
* List of manufacturer default SSIDs that are often unchanged by users. * List of manufacturer default SSIDs that are often unchanged by users.
* *
* NOTE: this list should *not* contain networks that you would like to * NOTE: this list should *not* contain networks that you would like to
* automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot". * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot".
*/ */
static const char * static const char *manf_defaults[] = {
manf_defaults[] = {
"linksys", "linksys",
"linksys-a", "linksys-a",
"linksys-g", "linksys-g",
@ -706,14 +718,7 @@ manf_defaults[] = {
"TURBONETT", "TURBONETT",
}; };
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) for (i = 0; i < G_N_ELEMENTS (manf_defaults); i++) {
static gboolean
is_manf_default_ssid (const GByteArray *ssid)
{
int i;
for (i = 0; i < ARRAY_SIZE (manf_defaults); i++) {
if (ssid->len == strlen (manf_defaults[i])) { if (ssid->len == strlen (manf_defaults[i])) {
if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0)
return TRUE; return TRUE;
@ -868,7 +873,7 @@ complete_connection (NMDevice *device,
if (hidden) if (hidden)
g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL);
perm_hw_addr = nm_device_get_permanent_hw_address (device); perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
if (perm_hw_addr) { if (perm_hw_addr) {
setting_mac = nm_setting_wireless_get_mac_address (s_wifi); setting_mac = nm_setting_wireless_get_mac_address (s_wifi);
if (setting_mac) { if (setting_mac) {
@ -1027,6 +1032,60 @@ impl_device_wifi_get_all_access_points (NMDeviceWifi *self,
g_ptr_array_unref (paths); g_ptr_array_unref (paths);
} }
static void
_hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset)
{
NMDevice *device = (NMDevice *) self;
NMDeviceWifiPrivate *priv;
guint32 now;
gboolean randomize;
g_return_if_fail (NM_IS_DEVICE_WIFI (self));
if ( nm_device_is_activating (device)
|| nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
return;
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
randomize = nm_config_data_get_device_config_boolean (NM_CONFIG_GET_DATA,
"wifi.scan-rand-mac-address",
device,
TRUE, TRUE);
if (!randomize) {
g_clear_pointer (&priv->hw_addr_scan, g_free);
if (do_reset)
nm_device_hw_addr_reset (device, "scanning");
return;
}
now = nm_utils_get_monotonic_timestamp_s ();
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
* it expires, instead on the next scan request, we will generate
* 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 (nm_device_get_initial_hw_address (device),
generate_mac_address_mask);
}
nm_device_hw_addr_set (device, priv->hw_addr_scan, "scanning");
}
static void static void
request_scan_cb (NMDevice *device, request_scan_cb (NMDevice *device,
GDBusMethodInvocation *context, GDBusMethodInvocation *context,
@ -1336,6 +1395,8 @@ request_wireless_scan (NMDeviceWifi *self, GVariant *scan_options)
_LOGD (LOGD_WIFI_SCAN, "no SSIDs to probe scan"); _LOGD (LOGD_WIFI_SCAN, "no SSIDs to probe scan");
} }
_hw_addr_set_scanning (self, FALSE);
if (nm_supplicant_interface_request_scan (priv->sup_iface, ssids)) { if (nm_supplicant_interface_request_scan (priv->sup_iface, ssids)) {
/* success */ /* success */
backoff = TRUE; backoff = TRUE;
@ -2210,9 +2271,6 @@ build_supplicant_config (NMDeviceWifi *self,
NMSupplicantConfig *config = NULL; NMSupplicantConfig *config = NULL;
NMSettingWireless *s_wireless; NMSettingWireless *s_wireless;
NMSettingWirelessSecurity *s_wireless_sec; NMSettingWirelessSecurity *s_wireless_sec;
NMSupplicantFeature mac_randomization_support;
NMSettingMacRandomization mac_randomization_fallback;
gs_free char *svalue = NULL;
g_return_val_if_fail (priv->sup_iface, NULL); g_return_val_if_fail (priv->sup_iface, NULL);
@ -2227,20 +2285,9 @@ build_supplicant_config (NMDeviceWifi *self,
_LOGW (LOGD_WIFI, "Supplicant may not support AP mode; connection may time out."); _LOGW (LOGD_WIFI, "Supplicant may not support AP mode; connection may time out.");
} }
mac_randomization_support = nm_supplicant_interface_get_mac_randomization_support (priv->sup_iface);
svalue = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
"wifi." NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION,
NM_DEVICE (self));
mac_randomization_fallback = _nm_utils_ascii_str_to_int64 (svalue, 10,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
NM_SETTING_MAC_RANDOMIZATION_ALWAYS,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT);
if (!nm_supplicant_config_add_setting_wireless (config, if (!nm_supplicant_config_add_setting_wireless (config,
s_wireless, s_wireless,
fixed_freq, fixed_freq,
mac_randomization_support,
mac_randomization_fallback,
error)) { error)) {
g_prefix_error (error, "802-11-wireless: "); g_prefix_error (error, "802-11-wireless: ");
goto error; goto error;
@ -2290,7 +2337,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
NMActRequest *req; NMActRequest *req;
NMConnection *connection; NMConnection *connection;
NMSettingWireless *s_wireless; NMSettingWireless *s_wireless;
const char *cloned_mac;
const char *mode; const char *mode;
const char *ap_path; const char *ap_path;
@ -2330,9 +2376,12 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
return NM_ACT_STAGE_RETURN_FAILURE; return NM_ACT_STAGE_RETURN_FAILURE;
} }
/* forget the temporary MAC address used during scanning */
g_clear_pointer (&priv->hw_addr_scan, g_free);
/* Set spoof MAC to the interface */ /* Set spoof MAC to the interface */
cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); if (!nm_device_hw_addr_set_cloned (device, connection, TRUE))
nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_WIFI); return NM_ACT_STAGE_RETURN_FAILURE;
/* AP mode never uses a specific object or existing scanned AP */ /* AP mode never uses a specific object or existing scanned AP */
if (priv->mode != NM_802_11_MODE_AP) { if (priv->mode != NM_802_11_MODE_AP) {
@ -2972,6 +3021,8 @@ finalize (GObject *object)
g_hash_table_unref (priv->aps); g_hash_table_unref (priv->aps);
g_free (priv->hw_addr_scan);
G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object);
} }
@ -2986,9 +3037,6 @@ get_property (GObject *object, guint prop_id,
GPtrArray *array; GPtrArray *array;
switch (prop_id) { switch (prop_id) {
case PROP_PERM_HW_ADDRESS:
g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (device)));
break;
case PROP_MODE: case PROP_MODE:
g_value_set_uint (value, priv->mode); g_value_set_uint (value, priv->mode);
break; break;
@ -3053,7 +3101,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
object_class->dispose = dispose; object_class->dispose = dispose;
object_class->finalize = finalize; object_class->finalize = finalize;
parent_class->realize_start_notify = realize_start_notify;
parent_class->bring_up = bring_up; parent_class->bring_up = bring_up;
parent_class->can_auto_connect = can_auto_connect; parent_class->can_auto_connect = can_auto_connect;
parent_class->is_available = is_available; parent_class->is_available = is_available;
@ -3070,19 +3117,13 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
parent_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; parent_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout;
parent_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; parent_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout;
parent_class->deactivate = deactivate; parent_class->deactivate = deactivate;
parent_class->unmanaged_on_quit = unmanaged_on_quit;
parent_class->state_changed = device_state_changed; parent_class->state_changed = device_state_changed;
klass->scanning_allowed = scanning_allowed; klass->scanning_allowed = scanning_allowed;
/* Properties */ /* Properties */
g_object_class_install_property
(object_class, PROP_PERM_HW_ADDRESS,
g_param_spec_string (NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, "", "",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property g_object_class_install_property
(object_class, PROP_MODE, (object_class, PROP_MODE,
g_param_spec_uint (NM_DEVICE_WIFI_MODE, "", "", g_param_spec_uint (NM_DEVICE_WIFI_MODE, "", "",

View file

@ -36,7 +36,6 @@ G_BEGIN_DECLS
#define NM_IS_DEVICE_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WIFI)) #define NM_IS_DEVICE_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WIFI))
#define NM_DEVICE_WIFI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass)) #define NM_DEVICE_WIFI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass))
#define NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS "perm-hw-address"
#define NM_DEVICE_WIFI_MODE "mode" #define NM_DEVICE_WIFI_MODE "mode"
#define NM_DEVICE_WIFI_BITRATE "bitrate" #define NM_DEVICE_WIFI_BITRATE "bitrate"
#define NM_DEVICE_WIFI_ACCESS_POINTS "access-points" #define NM_DEVICE_WIFI_ACCESS_POINTS "access-points"

View file

@ -40,7 +40,7 @@ typedef struct {
gboolean has; gboolean has;
GSList *spec; GSList *spec;
} match_device; } match_device;
} ConnectionInfo; } MatchSectionInfo;
typedef struct { typedef struct {
char *config_main_file; char *config_main_file;
@ -52,7 +52,11 @@ typedef struct {
/* A zero-terminated list of pre-processed information from the /* A zero-terminated list of pre-processed information from the
* [connection] sections. This is to speed up lookup. */ * [connection] sections. This is to speed up lookup. */
ConnectionInfo *connection_infos; MatchSectionInfo *connection_infos;
/* A zero-terminated list of pre-processed information from the
* [device] sections. This is to speed up lookup. */
MatchSectionInfo *device_infos;
struct { struct {
char *uri; char *uri;
@ -268,9 +272,16 @@ nm_config_data_get_rc_manager (const NMConfigData *self)
gboolean gboolean
nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device) nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device)
{ {
gs_free char *value = NULL;
gboolean has_match;
g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE); g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE);
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE); g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
value = nm_config_data_get_device_config (self, NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER, device, &has_match);
if (has_match)
return nm_config_parse_boolean (value, FALSE);
return nm_device_spec_match_list (device, NM_CONFIG_DATA_GET_PRIVATE (self)->ignore_carrier); return nm_device_spec_match_list (device, NM_CONFIG_DATA_GET_PRIVATE (self)->ignore_carrier);
} }
@ -451,6 +462,7 @@ static int
_nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy) _nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy)
{ {
gboolean a_is_connection, b_is_connection; gboolean a_is_connection, b_is_connection;
gboolean a_is_device, b_is_device;
gboolean a_is_intern, b_is_intern; gboolean a_is_intern, b_is_intern;
const char *a = *pa; const char *a = *pa;
const char *b = *pb; const char *b = *pb;
@ -488,6 +500,28 @@ _nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy)
if (b_is_connection && !a_is_connection) if (b_is_connection && !a_is_connection)
return -1; return -1;
/* we sort device groups before connection groups (to the end). */
a_is_device = a && g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
b_is_device = b && g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
if (a_is_device && b_is_device) {
/* if both are device groups, we want the explicit [device] group first. */
a_is_device = a[NM_STRLEN (NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)] == '\0';
b_is_device = b[NM_STRLEN (NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)] == '\0';
if (a_is_device != b_is_device) {
if (a_is_device)
return -1;
return 1;
}
/* the sections are ordered lowest-priority first. Reverse their order. */
return pa < pb ? 1 : -1;
}
if (a_is_device && !b_is_device)
return 1;
if (b_is_device && !a_is_device)
return -1;
/* no reordering. */ /* no reordering. */
return 0; return 0;
} }
@ -1049,25 +1083,18 @@ global_dns_equal (NMGlobalDnsConfig *old, NMGlobalDnsConfig *new)
/************************************************************************/ /************************************************************************/
char * static const MatchSectionInfo *
nm_config_data_get_connection_default (const NMConfigData *self, _match_section_infos_lookup (const MatchSectionInfo *match_section_infos,
GKeyFile *keyfile,
const char *property, const char *property,
NMDevice *device) NMDevice *device,
char **out_value)
{ {
NMConfigDataPrivate *priv; if (!match_section_infos)
const ConnectionInfo *connection_info;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (property && *property, NULL);
g_return_val_if_fail (strchr (property, '.'), NULL);
priv = NM_CONFIG_DATA_GET_PRIVATE (self);
if (!priv->connection_infos)
return NULL; return NULL;
for (connection_info = &priv->connection_infos[0]; connection_info->group_name; connection_info++) { for (; match_section_infos->group_name; match_section_infos++) {
char *value; char *value = NULL;
gboolean match; gboolean match;
/* FIXME: Here we use g_key_file_get_string(). This should be in sync with what keyfile-reader /* FIXME: Here we use g_key_file_get_string(). This should be in sync with what keyfile-reader
@ -1077,23 +1104,87 @@ nm_config_data_get_connection_default (const NMConfigData *self,
* string_to_value(keyfile_to_string(keyfile)) in one. Optimally, keyfile library would * string_to_value(keyfile_to_string(keyfile)) in one. Optimally, keyfile library would
* expose both functions, and we would return here keyfile_to_string(keyfile). * expose both functions, and we would return here keyfile_to_string(keyfile).
* The caller then could convert the string to the proper value via string_to_value(value). */ * The caller then could convert the string to the proper value via string_to_value(value). */
value = g_key_file_get_string (priv->keyfile, connection_info->group_name, property, NULL); value = g_key_file_get_string (keyfile, match_section_infos->group_name, property, NULL);
if (!value && !connection_info->stop_match) if (!value && !match_section_infos->stop_match)
continue; continue;
match = TRUE; match = TRUE;
if (connection_info->match_device.has) if (match_section_infos->match_device.has)
match = device && nm_device_spec_match_list (device, connection_info->match_device.spec); match = device && nm_device_spec_match_list (device, match_section_infos->match_device.spec);
if (match) if (match) {
return value; *out_value = value;
return match_section_infos;
}
g_free (value); g_free (value);
} }
return NULL; return NULL;
} }
char *
nm_config_data_get_device_config (const NMConfigData *self,
const char *property,
NMDevice *device,
gboolean *has_match)
{
NMConfigDataPrivate *priv;
const MatchSectionInfo *connection_info;
char *value = NULL;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (property && *property, NULL);
priv = NM_CONFIG_DATA_GET_PRIVATE (self);
connection_info = _match_section_infos_lookup (&priv->device_infos[0],
priv->keyfile,
property,
device,
&value);
NM_SET_OUT (has_match, !!connection_info);
return value;
}
gboolean
nm_config_data_get_device_config_boolean (const NMConfigData *self,
const char *property,
NMDevice *device,
gint val_no_match,
gint val_invalid)
{
gs_free char *value = NULL;
gboolean has_match;
value = nm_config_data_get_device_config (self, property, device, &has_match);
if (!has_match)
return val_no_match;
return nm_config_parse_boolean (value, val_invalid);
}
char *
nm_config_data_get_connection_default (const NMConfigData *self,
const char *property,
NMDevice *device)
{
NMConfigDataPrivate *priv;
char *value = NULL;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (property && *property, NULL);
g_return_val_if_fail (strchr (property, '.'), NULL);
priv = NM_CONFIG_DATA_GET_PRIVATE (self);
_match_section_infos_lookup (&priv->connection_infos[0],
priv->keyfile,
property,
device,
&value);
return value;
}
static void static void
_get_connection_info_init (ConnectionInfo *connection_info, GKeyFile *keyfile, char *group) _get_connection_info_init (MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group)
{ {
/* pass ownership of @group on... */ /* pass ownership of @group on... */
connection_info->group_name = group; connection_info->group_name = group;
@ -1105,27 +1196,43 @@ _get_connection_info_init (ConnectionInfo *connection_info, GKeyFile *keyfile, c
connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, group, "stop-match", FALSE); connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, group, "stop-match", FALSE);
} }
static ConnectionInfo * static void
_get_connection_infos (GKeyFile *keyfile) _match_section_infos_free (MatchSectionInfo *match_section_infos)
{
guint i;
if (!match_section_infos)
return;
for (i = 0; match_section_infos[i].group_name; i++) {
g_free (match_section_infos[i].group_name);
g_slist_free_full (match_section_infos[i].match_device.spec, g_free);
}
g_free (match_section_infos);
}
static MatchSectionInfo *
_match_section_infos_construct (GKeyFile *keyfile, const char *prefix)
{ {
char **groups; char **groups;
gsize i, j, ngroups; gsize i, j, ngroups;
char *connection_tag = NULL; char *connection_tag = NULL;
ConnectionInfo *connection_infos = NULL; MatchSectionInfo *match_section_infos = NULL;
/* get the list of existing [connection.\+] sections that we consider /* get the list of existing [connection.\+]/[device.\+] sections.
* for nm_config_data_get_connection_default().
* *
* We expect the sections in their right order, with lowest priority * We expect the sections in their right order, with lowest priority
* first. Only exception is the (literal) [connection] section, which * first. Only exception is the (literal) [connection] section, which
* we will always reorder to the end. */ * we will always reorder to the end. */
groups = g_key_file_get_groups (keyfile, &ngroups); groups = g_key_file_get_groups (keyfile, &ngroups);
if (!groups) if (!groups)
ngroups = 0; return NULL;
else if (ngroups > 0) {
if (ngroups > 0) {
gsize l = strlen (prefix);
for (i = 0, j = 0; i < ngroups; i++) { for (i = 0, j = 0; i < ngroups; i++) {
if (g_str_has_prefix (groups[i], NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION)) { if (g_str_has_prefix (groups[i], prefix)) {
if (groups[i][NM_STRLEN (NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION)] == '\0') if (groups[i][l] == '\0')
connection_tag = groups[i]; connection_tag = groups[i];
else else
groups[j++] = groups[i]; groups[j++] = groups[i];
@ -1135,18 +1242,23 @@ _get_connection_infos (GKeyFile *keyfile)
ngroups = j; ngroups = j;
} }
connection_infos = g_new0 (ConnectionInfo, ngroups + 1 + (connection_tag ? 1 : 0)); if (ngroups == 0 && !connection_tag) {
g_free (groups);
return NULL;
}
match_section_infos = g_new0 (MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0));
for (i = 0; i < ngroups; i++) { for (i = 0; i < ngroups; i++) {
/* pass ownership of @group on... */ /* pass ownership of @group on... */
_get_connection_info_init (&connection_infos[i], keyfile, groups[ngroups - i - 1]); _get_connection_info_init (&match_section_infos[i], keyfile, groups[ngroups - i - 1]);
} }
if (connection_tag) { if (connection_tag) {
/* pass ownership of @connection_tag on... */ /* pass ownership of @connection_tag on... */
_get_connection_info_init (&connection_infos[i], keyfile, connection_tag); _get_connection_info_init (&match_section_infos[i], keyfile, connection_tag);
} }
g_free (groups); g_free (groups);
return connection_infos; return match_section_infos;
} }
/************************************************************************/ /************************************************************************/
@ -1306,7 +1418,6 @@ static void
finalize (GObject *gobject) finalize (GObject *gobject)
{ {
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject); NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject);
guint i;
g_free (priv->config_main_file); g_free (priv->config_main_file);
g_free (priv->config_description); g_free (priv->config_description);
@ -1326,13 +1437,8 @@ finalize (GObject *gobject)
nm_global_dns_config_free (priv->global_dns); nm_global_dns_config_free (priv->global_dns);
if (priv->connection_infos) { _match_section_infos_free (priv->connection_infos);
for (i = 0; priv->connection_infos[i].group_name; i++) { _match_section_infos_free (priv->device_infos);
g_free (priv->connection_infos[i].group_name);
g_slist_free_full (priv->connection_infos[i].match_device.spec, g_free);
}
g_free (priv->connection_infos);
}
g_key_file_unref (priv->keyfile); g_key_file_unref (priv->keyfile);
if (priv->keyfile_user) if (priv->keyfile_user)
@ -1359,7 +1465,8 @@ constructed (GObject *object)
priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern); priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern);
priv->connection_infos = _get_connection_infos (priv->keyfile); priv->connection_infos = _match_section_infos_construct (priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
priv->device_infos = _match_section_infos_construct (priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL)); priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL));
priv->connectivity.response = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", NULL); priv->connectivity.response = g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", NULL);

View file

@ -183,6 +183,17 @@ char *nm_config_data_get_connection_default (const NMConfigData *self,
const char *property, const char *property,
NMDevice *device); NMDevice *device);
char *nm_config_data_get_device_config (const NMConfigData *self,
const char *property,
NMDevice *device,
gboolean *has_match);
gboolean nm_config_data_get_device_config_boolean (const NMConfigData *self,
const char *property,
NMDevice *device,
gint val_no_match,
gint val_invalid);
char **nm_config_data_get_groups (const NMConfigData *self); char **nm_config_data_get_groups (const NMConfigData *self);
char **nm_config_data_get_keys (const NMConfigData *self, const char *group); char **nm_config_data_get_keys (const NMConfigData *self, const char *group);
gboolean nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group); gboolean nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group);

View file

@ -399,7 +399,9 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
priv = NM_CONFIG_GET_PRIVATE (self); priv = NM_CONFIG_GET_PRIVATE (self);
hw_address = nm_device_get_hw_address (device); hw_address = nm_device_get_permanent_hw_address (device, FALSE);
if (!hw_address)
return;
no_auto_default_current = nm_config_data_get_no_auto_default (priv->config_data); no_auto_default_current = nm_config_data_get_no_auto_default (priv->config_data);
@ -576,14 +578,7 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy)
{ {
const char *a, *b; const char *a, *b;
gboolean a_is_connection, b_is_connection; gboolean a_is_connection, b_is_connection;
gboolean a_is_device, b_is_device;
/* basic NULL checking... */
if (pa == pb)
return 0;
if (!pa)
return -1;
if (!pb)
return 1;
a = *pa; a = *pa;
b = *pb; b = *pb;
@ -598,11 +593,7 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy)
return 1; return 1;
return -1; return -1;
} }
if (!a_is_connection) { if (a_is_connection) {
/* both are non-connection entries. Don't reorder. */
return 0;
}
/* both are [connection.\+] entires. Reverse their order. /* both are [connection.\+] entires. Reverse their order.
* One of the sections might be literally [connection]. That section * One of the sections might be literally [connection]. That section
* is special and it's order will be fixed later. It doesn't actually * is special and it's order will be fixed later. It doesn't actually
@ -610,6 +601,28 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy)
return pa > pb ? -1 : 1; return pa > pb ? -1 : 1;
} }
a_is_device = g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
b_is_device = g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
if (a_is_device != b_is_device) {
/* one is a [device*] entry, the other not. We sort [device*] entires
* after. */
if (a_is_device)
return 1;
return -1;
}
if (a_is_device) {
/* both are [device.\+] entires. Reverse their order.
* One of the sections might be literally [device]. That section
* is special and it's order will be fixed later. It doesn't actually
* matter here how it compares with [device.\+] sections. */
return pa > pb ? -1 : 1;
}
/* don't reorder the rest. */
return 0;
}
void void
_nm_config_sort_groups (char **groups, gsize ngroups) _nm_config_sort_groups (char **groups, gsize ngroups)
{ {
@ -630,7 +643,8 @@ _setting_is_device_spec (const char *group, const char *key)
|| _IS (NM_CONFIG_KEYFILE_GROUP_MAIN, "ignore-carrier") || _IS (NM_CONFIG_KEYFILE_GROUP_MAIN, "ignore-carrier")
|| _IS (NM_CONFIG_KEYFILE_GROUP_MAIN, "assume-ipv6ll-only") || _IS (NM_CONFIG_KEYFILE_GROUP_MAIN, "assume-ipv6ll-only")
|| _IS (NM_CONFIG_KEYFILE_GROUP_KEYFILE, "unmanaged-devices") || _IS (NM_CONFIG_KEYFILE_GROUP_KEYFILE, "unmanaged-devices")
|| (g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION) && !strcmp (key, "match-device")); || (g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION) && !strcmp (key, "match-device"))
|| (g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE ) && !strcmp (key, "match-device"));
} }
static gboolean static gboolean

View file

@ -45,6 +45,7 @@
#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN ".intern." #define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN ".intern."
#define NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION "connection" #define NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION "connection"
#define NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "device"
#define NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN "global-dns-domain-" #define NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN "global-dns-domain-"
#define NM_CONFIG_KEYFILE_GROUPPREFIX_TEST_APPEND_STRINGLIST ".test-append-stringlist" #define NM_CONFIG_KEYFILE_GROUPPREFIX_TEST_APPEND_STRINGLIST ".test-append-stringlist"
@ -69,6 +70,8 @@
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed" #define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_AUDIT "audit" #define NM_CONFIG_KEYFILE_KEY_AUDIT "audit"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier"
#define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was." #define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was."
#define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set." #define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set."

View file

@ -26,6 +26,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <resolv.h> #include <resolv.h>
@ -54,7 +55,7 @@
#endif #endif
G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int)); G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int));
int _nm_utils_testing = 0; static int _nm_utils_testing = 0;
gboolean gboolean
nm_utils_get_testing_initialized () nm_utils_get_testing_initialized ()
@ -1271,8 +1272,10 @@ nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
{ {
const GSList *iter; const GSList *iter;
NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
guint hwaddr_len = 0;
guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX];
g_return_val_if_fail (hwaddr != NULL, NM_MATCH_SPEC_NO_MATCH); nm_assert (nm_utils_hwaddr_valid (hwaddr, -1));
for (iter = specs; iter; iter = g_slist_next (iter)) { for (iter = specs; iter; iter = g_slist_next (iter)) {
const char *spec_str = iter->data; const char *spec_str = iter->data;
@ -1293,7 +1296,15 @@ nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr)
else if (except) else if (except)
continue; continue;
if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) { if (G_UNLIKELY (hwaddr_len == 0)) {
hwaddr_len = _nm_utils_hwaddr_length (hwaddr);
if (!hwaddr_len)
g_return_val_if_reached (NM_MATCH_SPEC_NO_MATCH);
if (!nm_utils_hwaddr_aton (hwaddr, hwaddr_bin, hwaddr_len))
nm_assert_not_reached ();
}
if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr_bin, hwaddr_len)) {
if (except) if (except)
return NM_MATCH_SPEC_NEG_MATCH; return NM_MATCH_SPEC_NEG_MATCH;
match = NM_MATCH_SPEC_MATCH; match = NM_MATCH_SPEC_MATCH;
@ -2701,6 +2712,123 @@ nm_utils_machine_id_read (void)
/*****************************************************************************/ /*****************************************************************************/
/* taken from systemd's fd_wait_for_event(). Note that the timeout
* is here in nano-seconds, not micro-seconds. */
int
nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_ns)
{
struct pollfd pollfd = {
.fd = fd,
.events = event,
};
struct timespec ts, *pts;
int r;
if (timeout_ns < 0)
pts = NULL;
else {
ts.tv_sec = (time_t) (timeout_ns / NM_UTILS_NS_PER_SECOND);
ts.tv_nsec = (long int) (timeout_ns % NM_UTILS_NS_PER_SECOND);
pts = &ts;
}
r = ppoll (&pollfd, 1, pts, NULL);
if (r < 0)
return -errno;
if (r == 0)
return 0;
return pollfd.revents;
}
/* taken from systemd's loop_read() */
ssize_t
nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll)
{
uint8_t *p = buf;
ssize_t n = 0;
g_return_val_if_fail (fd >= 0, -EINVAL);
g_return_val_if_fail (buf, -EINVAL);
/* If called with nbytes == 0, let's call read() at least
* once, to validate the operation */
if (nbytes > (size_t) SSIZE_MAX)
return -EINVAL;
do {
ssize_t k;
k = read (fd, p, nbytes);
if (k < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN && do_poll) {
/* We knowingly ignore any return value here,
* and expect that any error/EOF is reported
* via read() */
(void) nm_utils_fd_wait_for_event (fd, POLLIN, -1);
continue;
}
return n > 0 ? n : -errno;
}
if (k == 0)
return n;
g_assert ((size_t) k <= nbytes);
p += k;
nbytes -= k;
n += k;
} while (nbytes > 0);
return n;
}
/* taken from systemd's loop_read_exact() */
int
nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll)
{
ssize_t n;
n = nm_utils_fd_read_loop (fd, buf, nbytes, do_poll);
if (n < 0)
return (int) n;
if ((size_t) n != nbytes)
return -EIO;
return 0;
}
/* taken from systemd's dev_urandom(). */
int
nm_utils_read_urandom (void *p, size_t nbytes)
{
int fd = -1;
int r;
again:
fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
r = errno;
if (r == EINTR)
goto again;
return r == ENOENT ? -ENOSYS : -r;
}
r = nm_utils_fd_read_loop_exact (fd, p, nbytes, TRUE);
close (fd);
return r;
}
/*****************************************************************************/
guint8 * guint8 *
nm_utils_secret_key_read (gsize *out_key_len, GError **error) nm_utils_secret_key_read (gsize *out_key_len, GError **error)
{ {
@ -2719,34 +2847,28 @@ nm_utils_secret_key_read (gsize *out_key_len, GError **error)
key_len = 0; key_len = 0;
} }
} else { } else {
int urandom = open ("/dev/urandom", O_RDONLY); int r;
mode_t key_mask; mode_t key_mask;
if (urandom == -1) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Can't open /dev/urandom: %s", strerror (errno));
key_len = 0;
goto out;
}
/* RFC7217 mandates the key SHOULD be at least 128 bits. /* RFC7217 mandates the key SHOULD be at least 128 bits.
* Let's use twice as much. */ * Let's use twice as much. */
key_len = 32; key_len = 32;
secret_key = g_malloc (key_len); secret_key = g_malloc (key_len);
r = nm_utils_read_urandom (secret_key, key_len);
if (r < 0) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Can't read /dev/urandom: %s", strerror (-r));
key_len = 0;
goto out;
}
key_mask = umask (0077); key_mask = umask (0077);
if (read (urandom, secret_key, key_len) == key_len) {
if (!g_file_set_contents (NMSTATEDIR "/secret_key", (char *) secret_key, key_len, error)) { if (!g_file_set_contents (NMSTATEDIR "/secret_key", (char *) secret_key, key_len, error)) {
g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key: "); g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key: ");
key_len = 0; key_len = 0;
} }
} else {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Could not obtain a secret");
key_len = 0;
}
umask (key_mask); umask (key_mask);
close (urandom);
} }
out: out:
@ -2953,9 +3075,10 @@ nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, char *buf)
/*****************************************************************************/ /*****************************************************************************/
static gboolean static gboolean
_set_stable_privacy (struct in6_addr *addr, _set_stable_privacy (guint8 stable_type,
struct in6_addr *addr,
const char *ifname, const char *ifname,
const char *uuid, const char *network_id,
guint dad_counter, guint dad_counter,
guint8 *secret_key, guint8 *secret_key,
gsize key_len, gsize key_len,
@ -2979,11 +3102,24 @@ _set_stable_privacy (struct in6_addr *addr,
key_len = MIN (key_len, G_MAXUINT32); key_len = MIN (key_len, G_MAXUINT32);
if (stable_type != NM_UTILS_STABLE_TYPE_UUID) {
/* Preferably, we would always like to include the stable-type,
* but for backward compatibility reasons, we cannot for UUID.
*
* That is no real problem and it is still impossible to
* force a collision here, because of how the remaining
* fields are hashed. That is, as we also hash @key_len
* and the terminating '\0' of @network_id, it is unambigiously
* possible to revert the process and deduce the @stable_type.
*/
g_checksum_update (sum, &stable_type, sizeof (stable_type));
}
g_checksum_update (sum, addr->s6_addr, 8); g_checksum_update (sum, addr->s6_addr, 8);
g_checksum_update (sum, (const guchar *) ifname, strlen (ifname) + 1); g_checksum_update (sum, (const guchar *) ifname, strlen (ifname) + 1);
if (!uuid) if (!network_id)
uuid = ""; network_id = "";
g_checksum_update (sum, (const guchar *) uuid, strlen (uuid) + 1); g_checksum_update (sum, (const guchar *) network_id, strlen (network_id) + 1);
tmp[0] = htonl (dad_counter); tmp[0] = htonl (dad_counter);
tmp[1] = htonl (key_len); tmp[1] = htonl (key_len);
g_checksum_update (sum, (const guchar *) tmp, sizeof (tmp)); g_checksum_update (sum, (const guchar *) tmp, sizeof (tmp));
@ -3009,15 +3145,20 @@ _set_stable_privacy (struct in6_addr *addr,
* Returns: %TRUE on success, %FALSE if the address could not be generated. * Returns: %TRUE on success, %FALSE if the address could not be generated.
*/ */
gboolean gboolean
nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr, nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type,
struct in6_addr *addr,
const char *ifname, const char *ifname,
const char *uuid, const char *network_id,
guint dad_counter, guint dad_counter,
GError **error) GError **error)
{ {
gs_free guint8 *secret_key = NULL; gs_free guint8 *secret_key = NULL;
gsize key_len = 0; gsize key_len = 0;
nm_assert (NM_IN_SET (stable_type,
NM_UTILS_STABLE_TYPE_UUID,
NM_UTILS_STABLE_TYPE_STABLE_ID));
if (dad_counter >= RFC7217_IDGEN_RETRIES) { if (dad_counter >= RFC7217_IDGEN_RETRIES) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
"Too many DAD collisions"); "Too many DAD collisions");
@ -3028,10 +3169,151 @@ nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
if (!secret_key) if (!secret_key)
return FALSE; return FALSE;
return _set_stable_privacy (addr, ifname, uuid, dad_counter, return _set_stable_privacy (stable_type, addr, ifname, network_id, dad_counter,
secret_key, key_len, error); secret_key, key_len, error);
} }
/*****************************************************************************/
static void
_hw_addr_eth_complete (struct ether_addr *addr,
const char *current_mac_address,
const char *generate_mac_address_mask)
{
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". 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 (const char *current_mac_address,
const char *generate_mac_address_mask)
{
struct ether_addr bin_addr;
if (nm_utils_read_urandom (&bin_addr, ETH_ALEN) < 0)
return NULL;
_hw_addr_eth_complete (&bin_addr, current_mac_address, generate_mac_address_mask);
return nm_utils_hwaddr_ntoa (&bin_addr, ETH_ALEN);
}
static char *
_hw_addr_gen_stable_eth (NMUtilsStableType stable_type,
const char *stable_id,
const guint8 *secret_key,
gsize key_len,
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);
struct ether_addr bin_addr;
guint8 stable_type_uint8;
nm_assert (stable_id);
nm_assert (NM_IN_SET (stable_type,
NM_UTILS_STABLE_TYPE_UUID,
NM_UTILS_STABLE_TYPE_STABLE_ID));
nm_assert (secret_key);
sum = g_checksum_new (G_CHECKSUM_SHA256);
if (!sum)
return NULL;
key_len = MIN (key_len, G_MAXUINT32);
stable_type_uint8 = stable_type;
g_checksum_update (sum, (const guchar *) &stable_type_uint8, sizeof (stable_type_uint8));
tmp = htonl ((guint32) key_len);
g_checksum_update (sum, (const guchar *) &tmp, sizeof (tmp));
g_checksum_update (sum, (const guchar *) secret_key, key_len);
g_checksum_update (sum, (const guchar *) (ifname ?: ""), ifname ? (strlen (ifname) + 1) : 1);
g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1);
g_checksum_get_digest (sum, digest, &len);
g_checksum_free (sum);
g_return_val_if_fail (len == 32, NULL);
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 *current_mac_address,
const char *generate_mac_address_mask)
{
gs_free guint8 *secret_key = NULL;
gsize key_len = 0;
g_return_val_if_fail (stable_id, NULL);
secret_key = nm_utils_secret_key_read (&key_len, NULL);
if (!secret_key)
return NULL;
return _hw_addr_gen_stable_eth (stable_type,
stable_id,
secret_key,
key_len,
ifname,
current_mac_address,
generate_mac_address_mask);
}
/*****************************************************************************/
/** /**
* nm_utils_setpgid: * nm_utils_setpgid:
* @unused: unused * @unused: unused

View file

@ -310,6 +310,12 @@ const char *nm_utils_ip4_property_path (const char *ifname, const char *property
gboolean nm_utils_is_specific_hostname (const char *name); gboolean nm_utils_is_specific_hostname (const char *name);
int nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_ns);
ssize_t nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll);
int nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll);
int nm_utils_read_urandom (void *p, size_t n);
char *nm_utils_machine_id_read (void); char *nm_utils_machine_id_read (void);
gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid); gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid);
@ -353,12 +359,26 @@ gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
guint dev_id, guint dev_id,
NMUtilsIPv6IfaceId *out_iid); NMUtilsIPv6IfaceId *out_iid);
gboolean nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr, typedef enum {
NM_UTILS_STABLE_TYPE_UUID = 0,
NM_UTILS_STABLE_TYPE_STABLE_ID = 1,
} NMUtilsStableType;
gboolean nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType id_type,
struct in6_addr *addr,
const char *ifname, const char *ifname,
const char *uuid, const char *network_id,
guint dad_counter, guint dad_counter,
GError **error); GError **error);
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 *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); void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
void nm_utils_setpgid (gpointer unused); void nm_utils_setpgid (gpointer unused);

View file

@ -66,6 +66,7 @@ static struct {
int tempaddr; int tempaddr;
char *ifname; char *ifname;
char *uuid; char *uuid;
char *stable_id;
char *dhcp4_address; char *dhcp4_address;
char *dhcp4_clientid; char *dhcp4_clientid;
char *dhcp4_hostname; char *dhcp4_hostname;
@ -278,8 +279,9 @@ do_early_setup (int *argc, char **argv[])
gint64 priority64_v6 = -1; gint64 priority64_v6 = -1;
GOptionEntry options[] = { GOptionEntry options[] = {
/* Interface/IP config */ /* Interface/IP config */
{ "ifname", 'i', 0, G_OPTION_ARG_STRING, &global_opt.ifname, N_("The interface to manage"), N_("eth0") }, { "ifname", 'i', 0, G_OPTION_ARG_STRING, &global_opt.ifname, N_("The interface to manage"), "eth0" },
{ "uuid", 'u', 0, G_OPTION_ARG_STRING, &global_opt.uuid, N_("Connection UUID"), N_("661e8cd0-b618-46b8-9dc9-31a52baaa16b") }, { "uuid", 'u', 0, G_OPTION_ARG_STRING, &global_opt.uuid, N_("Connection UUID"), "661e8cd0-b618-46b8-9dc9-31a52baaa16b" },
{ "stable-id", '\0', 0, G_OPTION_ARG_STRING, &global_opt.stable_id, N_("Connection Token for Stable IDs"), "eth" },
{ "slaac", 's', 0, G_OPTION_ARG_NONE, &global_opt.slaac, N_("Whether to manage IPv6 SLAAC"), NULL }, { "slaac", 's', 0, G_OPTION_ARG_NONE, &global_opt.slaac, N_("Whether to manage IPv6 SLAAC"), NULL },
{ "slaac-required", '6', 0, G_OPTION_ARG_NONE, &global_opt.slaac_required, N_("Whether SLAAC must be successful"), NULL }, { "slaac-required", '6', 0, G_OPTION_ARG_NONE, &global_opt.slaac_required, N_("Whether SLAAC must be successful"), NULL },
{ "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &global_opt.tempaddr, N_("Use an IPv6 temporary privacy address"), NULL }, { "slaac-tempaddr", 't', 0, G_OPTION_ARG_INT, &global_opt.tempaddr, N_("Use an IPv6 temporary privacy address"), NULL },
@ -469,9 +471,23 @@ main (int argc, char *argv[])
} }
if (global_opt.slaac) { if (global_opt.slaac) {
NMUtilsStableType stable_type = NM_UTILS_STABLE_TYPE_UUID;
const char *stable_id = global_opt.uuid;
nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, TRUE); nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, TRUE);
rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, ifindex, global_opt.ifname, global_opt.uuid, global_opt.addr_gen_mode, NULL); if ( global_opt.stable_id
&& (global_opt.stable_id[0] >= '0' && global_opt.stable_id[0] <= '9')
&& global_opt.stable_id[1] == ' ') {
/* strict parsing of --stable-id, which is the numeric stable-type
* and the ID, joined with one space. For now, only support stable-types
* from 0 to 9. */
stable_type = (global_opt.stable_id[0] - '0');
stable_id = &global_opt.stable_id[2];
}
rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, ifindex, global_opt.ifname,
stable_type, stable_id,
global_opt.addr_gen_mode, NULL);
g_assert (rdisc); g_assert (rdisc);
if (iid) if (iid)

View file

@ -595,7 +595,7 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
} }
static NMDevice * static NMDevice *
find_device_by_hw_addr (NMManager *manager, const char *hwaddr) find_device_by_permanent_hw_addr (NMManager *manager, const char *hwaddr)
{ {
GSList *iter; GSList *iter;
const char *device_addr; const char *device_addr;
@ -604,7 +604,7 @@ find_device_by_hw_addr (NMManager *manager, const char *hwaddr)
if (nm_utils_hwaddr_valid (hwaddr, -1)) { if (nm_utils_hwaddr_valid (hwaddr, -1)) {
for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
device_addr = nm_device_get_hw_address (NM_DEVICE (iter->data)); device_addr = nm_device_get_permanent_hw_address (NM_DEVICE (iter->data), FALSE);
if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1)) if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1))
return NM_DEVICE (iter->data); return NM_DEVICE (iter->data);
} }
@ -945,28 +945,12 @@ remove_device (NMManager *self,
nm_device_get_iface (device), allow_unmanage, nm_device_get_managed (device, FALSE)); nm_device_get_iface (device), allow_unmanage, nm_device_get_managed (device, FALSE));
if (allow_unmanage && nm_device_get_managed (device, FALSE)) { if (allow_unmanage && nm_device_get_managed (device, FALSE)) {
unmanage = TRUE;
if (!quitting) { if (quitting)
unmanage = nm_device_unmanage_on_quit (device);
else {
/* the device is already gone. Unmanage it. */ /* the device is already gone. Unmanage it. */
} else { unmanage = TRUE;
/* Leave certain devices alone when quitting so their configuration
* can be taken over when NM restarts. This ensures connectivity while
* NM is stopped.
*/
if (nm_device_uses_assumed_connection (device)) {
/* An assume connection must be left alone */
unmanage = FALSE;
} else if (!nm_device_get_act_request (device)) {
/* a device without any active connection is either UNAVAILABLE or DISCONNECTED
* state. Since we don't know whether the device was upped by NetworkManager,
* we must leave it up on exit. */
unmanage = FALSE;
} else if (!nm_platform_link_can_assume (NM_PLATFORM_GET, nm_device_get_ifindex (device))) {
/* The device has no layer 3 configuration. Leave it up. */
unmanage = FALSE;
} else if (nm_device_can_assume_active_connection (device))
unmanage = FALSE;
} }
if (unmanage) { if (unmanage) {
@ -1054,7 +1038,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
return parent; return parent;
/* Maybe a hardware address */ /* Maybe a hardware address */
parent = find_device_by_hw_addr (self, parent_name); parent = find_device_by_permanent_hw_addr (self, parent_name);
if (parent) if (parent)
return parent; return parent;

View file

@ -321,7 +321,8 @@ NMRDisc *
nm_lndp_rdisc_new (NMPlatform *platform, nm_lndp_rdisc_new (NMPlatform *platform,
int ifindex, int ifindex,
const char *ifname, const char *ifname,
const char *uuid, NMUtilsStableType stable_type,
const char *network_id,
NMSettingIP6ConfigAddrGenMode addr_gen_mode, NMSettingIP6ConfigAddrGenMode addr_gen_mode,
GError **error) GError **error)
{ {
@ -342,7 +343,8 @@ nm_lndp_rdisc_new (NMPlatform *platform,
rdisc->ifindex = ifindex; rdisc->ifindex = ifindex;
rdisc->ifname = g_strdup (ifname); rdisc->ifname = g_strdup (ifname);
rdisc->uuid = g_strdup (uuid); rdisc->stable_type = stable_type;
rdisc->network_id = g_strdup (network_id);
rdisc->addr_gen_mode = addr_gen_mode; rdisc->addr_gen_mode = addr_gen_mode;
rdisc->max_addresses = ipv6_sysctl_get (platform, ifname, "max_addresses", rdisc->max_addresses = ipv6_sysctl_get (platform, ifname, "max_addresses",

View file

@ -22,6 +22,7 @@
#define __NETWORKMANAGER_LNDP_RDISC_H__ #define __NETWORKMANAGER_LNDP_RDISC_H__
#include "nm-rdisc.h" #include "nm-rdisc.h"
#include "nm-core-utils.h"
#define NM_TYPE_LNDP_RDISC (nm_lndp_rdisc_get_type ()) #define NM_TYPE_LNDP_RDISC (nm_lndp_rdisc_get_type ())
#define NM_LNDP_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LNDP_RDISC, NMLNDPRDisc)) #define NM_LNDP_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LNDP_RDISC, NMLNDPRDisc))
@ -47,7 +48,8 @@ GType nm_lndp_rdisc_get_type (void);
NMRDisc *nm_lndp_rdisc_new (NMPlatform *platform, NMRDisc *nm_lndp_rdisc_new (NMPlatform *platform,
int ifindex, int ifindex,
const char *ifname, const char *ifname,
const char *uuid, NMUtilsStableType stable_type,
const char *network_id,
NMSettingIP6ConfigAddrGenMode addr_gen_mode, NMSettingIP6ConfigAddrGenMode addr_gen_mode,
GError **error); GError **error);

View file

@ -140,9 +140,10 @@ complete_address (NMRDisc *rdisc, NMRDiscAddress *addr)
GError *error = NULL; GError *error = NULL;
if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
if (!nm_utils_ipv6_addr_set_stable_privacy (&addr->address, if (!nm_utils_ipv6_addr_set_stable_privacy (rdisc->stable_type,
&addr->address,
rdisc->ifname, rdisc->ifname,
rdisc->uuid, rdisc->network_id,
addr->dad_counter++, addr->dad_counter++,
&error)) { &error)) {
_LOGW ("complete-address: failed to generate an stable-privacy address: %s", _LOGW ("complete-address: failed to generate an stable-privacy address: %s",
@ -777,7 +778,7 @@ finalize (GObject *object)
NMRDisc *rdisc = NM_RDISC (object); NMRDisc *rdisc = NM_RDISC (object);
g_free (rdisc->ifname); g_free (rdisc->ifname);
g_free (rdisc->uuid); g_free (rdisc->network_id);
g_array_unref (rdisc->gateways); g_array_unref (rdisc->gateways);
g_array_unref (rdisc->addresses); g_array_unref (rdisc->addresses);
g_array_unref (rdisc->routes); g_array_unref (rdisc->routes);

View file

@ -116,9 +116,11 @@ typedef struct {
NMPlatform *_platform; NMPlatform *_platform;
NMPNetns *_netns; NMPNetns *_netns;
NMUtilsStableType stable_type;
int ifindex; int ifindex;
char *ifname; char *ifname;
char *uuid; char *network_id;
NMSettingIP6ConfigAddrGenMode addr_gen_mode; NMSettingIP6ConfigAddrGenMode addr_gen_mode;
NMUtilsIPv6IfaceId iid; NMUtilsIPv6IfaceId iid;
gint32 max_addresses; gint32 max_addresses;

View file

@ -64,6 +64,7 @@ main (int argc, char **argv)
rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET,
ifindex, ifindex,
ifname, ifname,
NM_UTILS_STABLE_TYPE_UUID,
"8ce666e8-d34d-4fb1-b858-f15a7al28086", "8ce666e8-d34d-4fb1-b858-f15a7al28086",
NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64,
&error); &error);

View file

@ -1879,11 +1879,11 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
NMSettingConnection *s_con; NMSettingConnection *s_con;
NMSettingWired *s_wired; NMSettingWired *s_wired;
const char *setting_hwaddr; const char *setting_hwaddr;
const char *device_hwaddr; const char *perm_hw_addr;
g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
device_hwaddr = nm_device_get_hw_address (device); perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE);
/* Find a wired connection locked to the given MAC address, if any */ /* Find a wired connection locked to the given MAC address, if any */
g_hash_table_iter_init (&iter, priv->connections); g_hash_table_iter_init (&iter, priv->connections);
@ -1917,8 +1917,8 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
setting_hwaddr = nm_setting_wired_get_mac_address (s_wired); setting_hwaddr = nm_setting_wired_get_mac_address (s_wired);
if (setting_hwaddr) { if (setting_hwaddr) {
/* A connection mac-locked to this device */ /* A connection mac-locked to this device */
if ( device_hwaddr if ( perm_hw_addr
&& nm_utils_hwaddr_matches (setting_hwaddr, -1, device_hwaddr, -1)) && nm_utils_hwaddr_matches (setting_hwaddr, -1, perm_hw_addr, -1))
return TRUE; return TRUE;
} else { } else {
/* A connection that applies to any wired device */ /* A connection that applies to any wired device */

View file

@ -128,6 +128,7 @@ make_connection_setting (const char *file,
NMSettingConnectionLldp lldp; NMSettingConnectionLldp lldp;
const char *ifcfg_name = NULL; const char *ifcfg_name = NULL;
char *new_id, *uuid = NULL, *zone = NULL, *value; char *new_id, *uuid = NULL, *zone = NULL, *value;
gs_free char *stable_id = NULL;
ifcfg_name = utils_get_ifcfg_name (file, TRUE); ifcfg_name = utils_get_ifcfg_name (file, TRUE);
if (!ifcfg_name) if (!ifcfg_name)
@ -146,9 +147,12 @@ make_connection_setting (const char *file,
uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
} }
stable_id = svGetValue (ifcfg, "STABLE_ID", FALSE);
g_object_set (s_con, g_object_set (s_con,
NM_SETTING_CONNECTION_TYPE, type, NM_SETTING_CONNECTION_TYPE, type,
NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_STABLE_ID, stable_id,
NULL); NULL);
g_free (uuid); g_free (uuid);
@ -3364,6 +3368,10 @@ make_wireless_setting (shvarFile *ifcfg,
g_free (value); 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); value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
if (value) { if (value) {
char **strv; char **strv;
@ -3878,6 +3886,10 @@ make_wired_setting (shvarFile *ifcfg,
g_free (value); 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); value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
if (value) { if (value) {
char **strv; char **strv;

View file

@ -853,6 +853,10 @@ write_wireless_setting (NMConnection *connection,
cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless);
svSetValue (ifcfg, "MACADDR", cloned_mac, FALSE); 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); svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE);
macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
if (macaddr_blacklist[0]) { 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); cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
svSetValue (ifcfg, "MACADDR", cloned_mac, FALSE); 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); svSetValue (ifcfg, "HWADDR_BLACKLIST", NULL, FALSE);
macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
if (macaddr_blacklist[0]) { if (macaddr_blacklist[0]) {
@ -1255,19 +1263,22 @@ write_wired_for_virtual (NMConnection *connection, shvarFile *ifcfg)
has_wired = TRUE; has_wired = TRUE;
device_mac = nm_setting_wired_get_mac_address (s_wired); device_mac = nm_setting_wired_get_mac_address (s_wired);
if (device_mac)
svSetValue (ifcfg, "HWADDR", device_mac, FALSE); svSetValue (ifcfg, "HWADDR", device_mac, FALSE);
cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired);
if (cloned_mac)
svSetValue (ifcfg, "MACADDR", cloned_mac, FALSE); 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); mtu = nm_setting_wired_get_mtu (s_wired);
if (mtu) { if (mtu) {
tmp = g_strdup_printf ("%u", mtu); tmp = g_strdup_printf ("%u", mtu);
svSetValue (ifcfg, "MTU", tmp, FALSE); svSetValue (ifcfg, "MTU", tmp, FALSE);
g_free (tmp); g_free (tmp);
} } else
svSetValue (ifcfg, "MTU", NULL, FALSE);
} }
return has_wired; return has_wired;
} }
@ -1800,6 +1811,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE); svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE);
svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE); svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE);
svSetValue (ifcfg, "STABLE_ID", nm_setting_connection_get_stable_id (s_con), FALSE);
svSetValue (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con), FALSE); svSetValue (ifcfg, "DEVICE", nm_setting_connection_get_interface_name (s_con), FALSE);
svSetValue (ifcfg, "ONBOOT", svSetValue (ifcfg, "ONBOOT",
nm_setting_connection_get_autoconnect (s_con) ? "yes" : "no", nm_setting_connection_get_autoconnect (s_con) ? "yes" : "no",

View file

@ -47,7 +47,6 @@ typedef struct
GHashTable *config; GHashTable *config;
GHashTable *blobs; GHashTable *blobs;
guint32 ap_scan; guint32 ap_scan;
NMSettingMacRandomization mac_randomization;
gboolean fast_required; gboolean fast_required;
gboolean dispose_has_run; gboolean dispose_has_run;
} NMSupplicantConfigPrivate; } NMSupplicantConfigPrivate;
@ -85,7 +84,6 @@ nm_supplicant_config_init (NMSupplicantConfig * self)
(GDestroyNotify) blob_free); (GDestroyNotify) blob_free);
priv->ap_scan = 1; priv->ap_scan = 1;
priv->mac_randomization = NM_SETTING_MAC_RANDOMIZATION_DEFAULT;
priv->dispose_has_run = FALSE; priv->dispose_has_run = FALSE;
} }
@ -272,32 +270,6 @@ nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self)
return NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan; return NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan;
} }
const char *
nm_supplicant_config_get_mac_randomization (NMSupplicantConfig *self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), 0);
/**
* mac_addr - MAC address policy default
*
* 0 = use permanent MAC address
* 1 = use random MAC address for each ESS connection
* 2 = like 1, but maintain OUI (with local admin bit set)
*
* By default, permanent MAC address is used unless policy is changed by
* the per-network mac_addr parameter.
*/
switch (NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->mac_randomization) {
case NM_SETTING_MAC_RANDOMIZATION_ALWAYS:
return "1";
case NM_SETTING_MAC_RANDOMIZATION_NEVER:
case NM_SETTING_MAC_RANDOMIZATION_DEFAULT:
default:
return "0";
}
}
gboolean gboolean
nm_supplicant_config_fast_required (NMSupplicantConfig *self) nm_supplicant_config_fast_required (NMSupplicantConfig *self)
{ {
@ -385,8 +357,6 @@ gboolean
nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
NMSettingWireless * setting, NMSettingWireless * setting,
guint32 fixed_freq, guint32 fixed_freq,
NMSupplicantFeature mac_randomization_support,
NMSettingMacRandomization mac_randomization_fallback,
GError **error) GError **error)
{ {
NMSupplicantConfigPrivate *priv; NMSupplicantConfigPrivate *priv;
@ -477,23 +447,6 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self,
} }
} }
priv->mac_randomization = nm_setting_wireless_get_mac_address_randomization (setting);
if (priv->mac_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) {
priv->mac_randomization = mac_randomization_fallback;
if (priv->mac_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) {
/* Don't use randomization, unless explicitly enabled.
* Randomization can work badly with captive portals. */
priv->mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER;
}
}
if ( priv->mac_randomization != NM_SETTING_MAC_RANDOMIZATION_NEVER
&& mac_randomization_support != NM_SUPPLICANT_FEATURE_YES) {
g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
"cannot enable mac-randomization due to missing supplicant support");
return FALSE;
}
return TRUE; return TRUE;
} }

View file

@ -54,8 +54,6 @@ NMSupplicantConfig *nm_supplicant_config_new (void);
guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self); guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
const char *nm_supplicant_config_get_mac_randomization (NMSupplicantConfig *self);
gboolean nm_supplicant_config_fast_required (NMSupplicantConfig *self); gboolean nm_supplicant_config_fast_required (NMSupplicantConfig *self);
GVariant *nm_supplicant_config_to_variant (NMSupplicantConfig *self); GVariant *nm_supplicant_config_to_variant (NMSupplicantConfig *self);
@ -65,8 +63,6 @@ GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self);
gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self, gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self,
NMSettingWireless *setting, NMSettingWireless *setting,
guint32 fixed_freq, guint32 fixed_freq,
NMSupplicantFeature mac_randomization_support,
NMSettingMacRandomization mac_randomization_fallback,
GError **error); GError **error);
gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,

View file

@ -503,12 +503,6 @@ nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
priv->ap_support = ap_support; priv->ap_support = ap_support;
} }
NMSupplicantFeature
nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *self)
{
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->mac_randomization_support;
}
static void static void
set_preassoc_scan_mac_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) set_preassoc_scan_mac_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{ {
@ -563,7 +557,7 @@ iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data
g_variant_new ("(ssv)", g_variant_new ("(ssv)",
WPAS_DBUS_IFACE_INTERFACE, WPAS_DBUS_IFACE_INTERFACE,
"PreassocMacAddr", "PreassocMacAddr",
g_variant_new_string ("1")), g_variant_new_string ("0")),
G_DBUS_CALL_FLAGS_NONE, G_DBUS_CALL_FLAGS_NONE,
-1, -1,
priv->init_cancellable, priv->init_cancellable,
@ -1223,9 +1217,7 @@ set_mac_randomization_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user
return; return;
} }
_LOGI ("config: set MAC randomization to %s", _LOGT ("config: set MAC randomization to 0");
nm_supplicant_config_get_mac_randomization (priv->cfg));
add_network (self); add_network (self);
} }
@ -1256,24 +1248,21 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
nm_supplicant_config_get_ap_scan (priv->cfg)); nm_supplicant_config_get_ap_scan (priv->cfg));
if (priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_YES) { if (priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_YES) {
const char *mac_randomization = nm_supplicant_config_get_mac_randomization (priv->cfg);
/* Enable/disable association MAC address randomization */ /* Enable/disable association MAC address randomization */
g_dbus_proxy_call (priv->iface_proxy, g_dbus_proxy_call (priv->iface_proxy,
DBUS_INTERFACE_PROPERTIES ".Set", DBUS_INTERFACE_PROPERTIES ".Set",
g_variant_new ("(ssv)", g_variant_new ("(ssv)",
WPAS_DBUS_IFACE_INTERFACE, WPAS_DBUS_IFACE_INTERFACE,
"MacAddr", "MacAddr",
g_variant_new_string (mac_randomization)), g_variant_new_string ("0")),
G_DBUS_CALL_FLAGS_NONE, G_DBUS_CALL_FLAGS_NONE,
-1, -1,
priv->assoc_cancellable, priv->assoc_cancellable,
(GAsyncReadyCallback) set_mac_randomization_cb, (GAsyncReadyCallback) set_mac_randomization_cb,
self); self);
} else { } else
add_network (self); add_network (self);
} }
}
gboolean gboolean
nm_supplicant_interface_set_config (NMSupplicantInterface *self, nm_supplicant_interface_set_config (NMSupplicantInterface *self,

View file

@ -165,6 +165,4 @@ NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterfac
void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self,
NMSupplicantFeature apmode); NMSupplicantFeature apmode);
NMSupplicantFeature nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *self);
#endif /* NM_SUPPLICANT_INTERFACE_H */ #endif /* NM_SUPPLICANT_INTERFACE_H */

View file

@ -160,8 +160,6 @@ test_wifi_open (void)
g_assert (nm_supplicant_config_add_setting_wireless (config, g_assert (nm_supplicant_config_add_setting_wireless (config,
s_wifi, s_wifi,
0, 0,
NM_SUPPLICANT_FEATURE_UNKNOWN,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
&error)); &error));
g_assert_no_error (error); g_assert_no_error (error);
g_test_assert_expected_messages (); g_test_assert_expected_messages ();
@ -265,8 +263,6 @@ test_wifi_wep_key (const char *detail,
g_assert (nm_supplicant_config_add_setting_wireless (config, g_assert (nm_supplicant_config_add_setting_wireless (config,
s_wifi, s_wifi,
0, 0,
NM_SUPPLICANT_FEATURE_UNKNOWN,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
&error)); &error));
g_assert_no_error (error); g_assert_no_error (error);
g_test_assert_expected_messages (); g_test_assert_expected_messages ();
@ -410,8 +406,6 @@ test_wifi_wpa_psk (const char *detail,
g_assert (nm_supplicant_config_add_setting_wireless (config, g_assert (nm_supplicant_config_add_setting_wireless (config,
s_wifi, s_wifi,
0, 0,
NM_SUPPLICANT_FEATURE_UNKNOWN,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
&error)); &error));
g_assert_no_error (error); g_assert_no_error (error);
g_test_assert_expected_messages (); g_test_assert_expected_messages ();
@ -557,8 +551,6 @@ test_wifi_eap (void)
g_assert (nm_supplicant_config_add_setting_wireless (config, g_assert (nm_supplicant_config_add_setting_wireless (config,
s_wifi, s_wifi,
0, 0,
NM_SUPPLICANT_FEATURE_UNKNOWN,
NM_SETTING_MAC_RANDOMIZATION_DEFAULT,
&error)); &error));
g_assert_no_error (error); g_assert_no_error (error);
g_test_assert_expected_messages (); g_test_assert_expected_messages ();

View file

@ -38,17 +38,6 @@ nm_test_device_init (NMTestDevice *self)
/* We jump over NMDevice's construct/destruct methods, which require NMPlatform /* We jump over NMDevice's construct/destruct methods, which require NMPlatform
* and NMConnectionProvider to be initialized. * and NMConnectionProvider to be initialized.
*/ */
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
return PARENT_CLASS->constructor (type,
n_construct_params,
construct_params);
}
static void static void
constructed (GObject *object) constructed (GObject *object)
{ {
@ -73,7 +62,6 @@ nm_test_device_class_init (NMTestDeviceClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
object_class->constructor = constructor;
object_class->constructed = constructed; object_class->constructed = constructed;
object_class->dispose = dispose; object_class->dispose = dispose;
@ -85,6 +73,6 @@ nm_test_device_new (const char *hwaddr)
{ {
return g_object_new (NM_TYPE_TEST_DEVICE, return g_object_new (NM_TYPE_TEST_DEVICE,
NM_DEVICE_IFACE, "dummy", NM_DEVICE_IFACE, "dummy",
NM_DEVICE_HW_ADDRESS, hwaddr, NM_DEVICE_PERM_HW_ADDRESS, hwaddr,
NULL); NULL);
} }

View file

@ -34,21 +34,93 @@ test_stable_privacy (void)
struct in6_addr addr1; struct in6_addr addr1;
inet_pton (AF_INET6, "1234::", &addr1); inet_pton (AF_INET6, "1234::", &addr1);
_set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, (guint8 *) "key", 3, NULL); _set_stable_privacy (NM_UTILS_STABLE_TYPE_UUID, &addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1234::4ceb:14cd:3d54:793f"); nmtst_assert_ip6_address (&addr1, "1234::4ceb:14cd:3d54:793f");
/* We get an address without the UUID. */ /* We get an address without the UUID. */
inet_pton (AF_INET6, "1::", &addr1); inet_pton (AF_INET6, "1::", &addr1);
_set_stable_privacy (&addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL); _set_stable_privacy (NM_UTILS_STABLE_TYPE_UUID, &addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1::11aa:2530:9144:dafa"); nmtst_assert_ip6_address (&addr1, "1::11aa:2530:9144:dafa");
/* We get a different address in a different network. */ /* We get a different address in a different network. */
inet_pton (AF_INET6, "2::", &addr1); inet_pton (AF_INET6, "2::", &addr1);
_set_stable_privacy (&addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL); _set_stable_privacy (NM_UTILS_STABLE_TYPE_UUID, &addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "2::338e:8d:c11:8726"); nmtst_assert_ip6_address (&addr1, "2::338e:8d:c11:8726");
inet_pton (AF_INET6, "1234::", &addr1);
_set_stable_privacy (NM_UTILS_STABLE_TYPE_STABLE_ID, &addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1234::ad4c:ae44:3d30:af1e");
inet_pton (AF_INET6, "1234::", &addr1);
_set_stable_privacy (NM_UTILS_STABLE_TYPE_STABLE_ID, &addr1, "eth666", "stable-id-1", 0, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1234::4944:67b0:7a6c:1cf");
} }
/*******************************************/ /*****************************************************************************/
static void
_do_test_hw_addr (NMUtilsStableType stable_type,
const char *stable_id,
const guint8 *secret_key,
gsize key_len,
const char *ifname,
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;
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,
current_mac_address,
generate_mac_address_mask);
g_assert (generated);
g_assert (nm_utils_hwaddr_valid (generated, ETH_ALEN));
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, 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", "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");
}
/*****************************************************************************/
NMTST_DEFINE (); NMTST_DEFINE ();
@ -58,6 +130,7 @@ main (int argc, char **argv)
nmtst_init_with_logging (&argc, &argv, NULL, "ALL"); nmtst_init_with_logging (&argc, &argv, NULL, "ALL");
g_test_add_func ("/utils/stable_privacy", test_stable_privacy); g_test_add_func ("/utils/stable_privacy", test_stable_privacy);
g_test_add_func ("/utils/hw_addr_gen_stable_eth", test_hw_addr_gen_stable_eth);
return g_test_run (); return g_test_run ();
} }