diff --git a/cli/src/connections.c b/cli/src/connections.c index e9aa597d11..b0d9883cdd 100644 --- a/cli/src/connections.c +++ b/cli/src/connections.c @@ -713,7 +713,7 @@ check_ethernet_compatible (NMDeviceEthernet *device, NMConnection *connection, G const char *device_mac_str; struct ether_addr *device_mac; - device_mac_str = nm_device_ethernet_get_hw_address (device); + device_mac_str = nm_device_ethernet_get_permanent_hw_address (device); device_mac = ether_aton (device_mac_str); if (!device_mac) { g_set_error (error, 0, 0, "Invalid device MAC address."); @@ -762,7 +762,7 @@ check_wifi_compatible (NMDeviceWifi *device, NMConnection *connection, GError ** const char *device_mac_str; struct ether_addr *device_mac; - device_mac_str = nm_device_wifi_get_hw_address (device); + device_mac_str = nm_device_wifi_get_permanent_hw_address (device); device_mac = ether_aton (device_mac_str); if (!device_mac) { g_set_error (error, 0, 0, "Invalid device MAC address."); diff --git a/cli/src/settings.c b/cli/src/settings.c index 1371bfbef5..8b62876479 100644 --- a/cli/src/settings.c +++ b/cli/src/settings.c @@ -50,13 +50,14 @@ static NmcOutputField nmc_fields_setting_connection[] = { /* Available fields for NM_SETTING_WIRED_SETTING_NAME */ static NmcOutputField nmc_fields_setting_wired[] = { - SETTING_FIELD ("name", 17), /* 0 */ - SETTING_FIELD (NM_SETTING_WIRED_PORT, 8), /* 1 */ - SETTING_FIELD (NM_SETTING_WIRED_SPEED, 10), /* 2 */ - SETTING_FIELD (NM_SETTING_WIRED_DUPLEX, 10), /* 3 */ - SETTING_FIELD (NM_SETTING_WIRED_AUTO_NEGOTIATE, 15), /* 4 */ - SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS, 19), /* 5 */ - SETTING_FIELD (NM_SETTING_WIRED_MTU, 6), /* 6 */ + SETTING_FIELD ("name", 17), /* 0 */ + SETTING_FIELD (NM_SETTING_WIRED_PORT, 8), /* 1 */ + SETTING_FIELD (NM_SETTING_WIRED_SPEED, 10), /* 2 */ + SETTING_FIELD (NM_SETTING_WIRED_DUPLEX, 10), /* 3 */ + SETTING_FIELD (NM_SETTING_WIRED_AUTO_NEGOTIATE, 15), /* 4 */ + SETTING_FIELD (NM_SETTING_WIRED_MAC_ADDRESS, 19), /* 5 */ + SETTING_FIELD (NM_SETTING_WIRED_CLONED_MAC_ADDRESS, 19), /* 6 */ + SETTING_FIELD (NM_SETTING_WIRED_MTU, 6), /* 7 */ {NULL, NULL, 0, NULL, 0} }; #define NMC_FIELDS_SETTING_WIRED_ALL "name"","\ @@ -65,6 +66,7 @@ static NmcOutputField nmc_fields_setting_wired[] = { NM_SETTING_WIRED_DUPLEX","\ NM_SETTING_WIRED_AUTO_NEGOTIATE","\ NM_SETTING_WIRED_MAC_ADDRESS","\ + NM_SETTING_WIRED_CLONED_MAC_ADDRESS","\ NM_SETTING_WIRED_MTU #define NMC_FIELDS_SETTING_WIRED_COMMON NMC_FIELDS_SETTING_WIRED_ALL @@ -131,9 +133,10 @@ static NmcOutputField nmc_fields_setting_wireless[] = { SETTING_FIELD (NM_SETTING_WIRELESS_RATE, 10), /* 6 */ SETTING_FIELD (NM_SETTING_WIRELESS_TX_POWER, 10), /* 7 */ SETTING_FIELD (NM_SETTING_WIRELESS_MAC_ADDRESS, 19), /* 8 */ - SETTING_FIELD (NM_SETTING_WIRELESS_MTU, 6), /* 9 */ - SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS, 35), /* 10 */ - SETTING_FIELD (NM_SETTING_WIRELESS_SEC, 10), /* 11 */ + SETTING_FIELD (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, 19), /* 9 */ + SETTING_FIELD (NM_SETTING_WIRELESS_MTU, 6), /* 10 */ + SETTING_FIELD (NM_SETTING_WIRELESS_SEEN_BSSIDS, 35), /* 11 */ + SETTING_FIELD (NM_SETTING_WIRELESS_SEC, 10), /* 12 */ {NULL, NULL, 0, NULL, 0} }; #define NMC_FIELDS_SETTING_WIRELESS_ALL "name"","\ @@ -145,6 +148,7 @@ static NmcOutputField nmc_fields_setting_wireless[] = { NM_SETTING_WIRELESS_RATE","\ NM_SETTING_WIRELESS_TX_POWER","\ NM_SETTING_WIRELESS_MAC_ADDRESS","\ + NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS","\ NM_SETTING_WIRELESS_MTU","\ NM_SETTING_WIRELESS_SEEN_BSSIDS","\ NM_SETTING_WIRELESS_SEC @@ -518,7 +522,7 @@ setting_wired_details (NMSetting *setting, NmCli *nmc) { NMSettingWired *s_wired; const GByteArray *mac; - char *speed_str, *mtu_str, *mac_str = NULL; + char *speed_str, *mtu_str, *device_mac_str = NULL, *cloned_mac_str = NULL; guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0; guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0; @@ -535,21 +539,26 @@ setting_wired_details (NMSetting *setting, NmCli *nmc) mtu_str = g_strdup_printf ("%d", nm_setting_wired_get_mtu (s_wired)); mac = nm_setting_wired_get_mac_address (s_wired); if (mac) - mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); + device_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); + mac = nm_setting_wired_get_cloned_mac_address (s_wired); + if (mac) + cloned_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); nmc->allowed_fields[0].value = NM_SETTING_WIRED_SETTING_NAME; nmc->allowed_fields[1].value = nm_setting_wired_get_port (s_wired); nmc->allowed_fields[2].value = speed_str; nmc->allowed_fields[3].value = nm_setting_wired_get_duplex (s_wired); nmc->allowed_fields[4].value = nm_setting_wired_get_auto_negotiate (s_wired) ? _("yes") : _("no"); - nmc->allowed_fields[5].value = mac_str; - nmc->allowed_fields[6].value = strcmp (mtu_str, "0") ? mtu_str : _("auto"); + nmc->allowed_fields[5].value = device_mac_str; + nmc->allowed_fields[6].value = cloned_mac_str; + nmc->allowed_fields[7].value = strcmp (mtu_str, "0") ? mtu_str : _("auto"); nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX; print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */ g_free (speed_str); - g_free (mac_str); + g_free (device_mac_str); + g_free (cloned_mac_str); g_free (mtu_str); return TRUE; @@ -663,7 +672,7 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc) int i; const GByteArray *ssid, *bssid, *mac; char *ssid_str, *channel_str, *rate_str, *tx_power_str, *mtu_str; - char *mac_str = NULL, *bssid_str = NULL; + char *device_mac_str = NULL, *cloned_mac_str = NULL, *bssid_str = NULL; GString *seen_bssids; guint32 mode_flag = (nmc->print_output == NMC_PRINT_PRETTY) ? NMC_PF_FLAG_PRETTY : (nmc->print_output == NMC_PRINT_TERSE) ? NMC_PF_FLAG_TERSE : 0; guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; @@ -688,7 +697,10 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc) mtu_str = g_strdup_printf ("%d", nm_setting_wireless_get_mtu (s_wireless)); mac = nm_setting_wireless_get_mac_address (s_wireless); if (mac) - mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); + device_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); + mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); + if (mac) + cloned_mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]); seen_bssids = g_string_new (NULL); for (i = 0; i < nm_setting_wireless_get_num_seen_bssids (s_wireless); i++) { if (i > 0) @@ -704,10 +716,11 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc) nmc->allowed_fields[5].value = bssid_str ? bssid_str : _("not set"); nmc->allowed_fields[6].value = rate_str; nmc->allowed_fields[7].value = tx_power_str; - nmc->allowed_fields[8].value = mac_str ? mac_str : _("not set"); - nmc->allowed_fields[9].value = strcmp (mtu_str, "0") ? mtu_str : _("auto"); - nmc->allowed_fields[10].value = seen_bssids->str; - nmc->allowed_fields[11].value = nm_setting_wireless_get_security (s_wireless); + nmc->allowed_fields[8].value = device_mac_str ? device_mac_str : _("not set"); + nmc->allowed_fields[9].value = cloned_mac_str ? cloned_mac_str : _("not set"); + nmc->allowed_fields[10].value = strcmp (mtu_str, "0") ? mtu_str : _("auto"); + nmc->allowed_fields[11].value = seen_bssids->str; + nmc->allowed_fields[12].value = nm_setting_wireless_get_security (s_wireless); nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_SECTION_PREFIX; print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */ @@ -717,7 +730,8 @@ setting_wireless_details (NMSetting *setting, NmCli *nmc) g_free (bssid_str); g_free (rate_str); g_free (tx_power_str); - g_free (mac_str); + g_free (device_mac_str); + g_free (cloned_mac_str); g_free (mtu_str); g_string_free (seen_bssids, TRUE); diff --git a/introspection/nm-device-ethernet.xml b/introspection/nm-device-ethernet.xml index 5b7c88ebfd..000caf752f 100644 --- a/introspection/nm-device-ethernet.xml +++ b/introspection/nm-device-ethernet.xml @@ -5,7 +5,13 @@ - Hardware address of the device. + Active hardware address of the device. + + + + + + Permanent hardware address of the device. diff --git a/introspection/nm-device-wifi.xml b/introspection/nm-device-wifi.xml index 21ace0a49e..fb50762438 100644 --- a/introspection/nm-device-wifi.xml +++ b/introspection/nm-device-wifi.xml @@ -16,9 +16,16 @@ - The hardware address of the device. + The active hardware address of the device. + + + + The permanent hardware address of the device. + + + The operating mode of the wireless device. diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am index e230a7c149..6462766b6e 100644 --- a/libnm-glib/Makefile.am +++ b/libnm-glib/Makefile.am @@ -132,7 +132,7 @@ libnm_glib_la_LIBADD = \ $(GUDEV_LIBS) libnm_glib_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib.ver \ - -version-info "5:0:3" + -version-info "6:0:4" noinst_PROGRAMS = libnm-glib-test diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver index 1c4d8f43c7..1596afaad9 100644 --- a/libnm-glib/libnm-glib.ver +++ b/libnm-glib/libnm-glib.ver @@ -63,6 +63,7 @@ global: nm_device_bt_get_type; nm_device_ethernet_get_carrier; nm_device_ethernet_get_hw_address; + nm_device_ethernet_get_permanent_hw_address; nm_device_ethernet_get_speed; nm_device_ethernet_get_type; nm_device_ethernet_new; @@ -86,6 +87,7 @@ global: nm_device_wifi_get_bitrate; nm_device_wifi_get_capabilities; nm_device_wifi_get_hw_address; + nm_device_wifi_get_permanent_hw_address; nm_device_wifi_get_mode; nm_device_wifi_get_type; nm_device_wifi_new; diff --git a/libnm-glib/nm-device-ethernet.c b/libnm-glib/nm-device-ethernet.c index 7a0cd925d0..44b2742765 100644 --- a/libnm-glib/nm-device-ethernet.c +++ b/libnm-glib/nm-device-ethernet.c @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. */ #include "nm-device-ethernet.h" @@ -34,7 +34,8 @@ G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE) typedef struct { DBusGProxy *proxy; - char * hw_address; + char *hw_address; + char *perm_hw_address; guint32 speed; gboolean carrier; gboolean carrier_valid; @@ -45,6 +46,7 @@ typedef struct { enum { PROP_0, PROP_HW_ADDRESS, + PROP_PERM_HW_ADDRESS, PROP_SPEED, PROP_CARRIER, @@ -52,6 +54,7 @@ enum { }; #define DBUS_PROP_HW_ADDRESS "HwAddress" +#define DBUS_PROP_PERM_HW_ADDRESS "PermHwAddress" #define DBUS_PROP_SPEED "Speed" #define DBUS_PROP_CARRIER "Carrier" @@ -80,9 +83,9 @@ nm_device_ethernet_new (DBusGConnection *connection, const char *path) * nm_device_ethernet_get_hw_address: * @device: a #NMDeviceEthernet * - * Gets the hardware (MAC) address of the #NMDeviceEthernet + * Gets the active hardware (MAC) address of the #NMDeviceEthernet * - * Returns: the hardware address. This is the internal string used by the + * Returns: the active hardware address. This is the internal string used by the * device, and must not be modified. **/ const char * @@ -102,6 +105,32 @@ nm_device_ethernet_get_hw_address (NMDeviceEthernet *device) return priv->hw_address; } +/** + * nm_device_ethernet_get_permanent_hw_address: + * @device: a #NMDeviceEthernet + * + * Gets the permanent hardware (MAC) address of the #NMDeviceEthernet + * + * Returns: the permanent hardware address. This is the internal string used by the + * device, and must not be modified. + **/ +const char * +nm_device_ethernet_get_permanent_hw_address (NMDeviceEthernet *device) +{ + NMDeviceEthernetPrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE_ETHERNET (device), NULL); + + priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); + if (!priv->perm_hw_address) { + priv->perm_hw_address = _nm_object_get_string_property (NM_OBJECT (device), + NM_DBUS_INTERFACE_DEVICE_WIRED, + DBUS_PROP_PERM_HW_ADDRESS); + } + + return priv->perm_hw_address; +} + /** * nm_device_ethernet_get_speed: * @device: a #NMDeviceEthernet @@ -168,9 +197,10 @@ register_for_property_changed (NMDeviceEthernet *device) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); const NMPropertiesChangedInfo property_changed_info[] = { - { NM_DEVICE_ETHERNET_HW_ADDRESS, _nm_object_demarshal_generic, &priv->hw_address }, - { NM_DEVICE_ETHERNET_SPEED, _nm_object_demarshal_generic, &priv->speed }, - { NM_DEVICE_ETHERNET_CARRIER, _nm_object_demarshal_generic, &priv->carrier }, + { NM_DEVICE_ETHERNET_HW_ADDRESS, _nm_object_demarshal_generic, &priv->hw_address }, + { NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, _nm_object_demarshal_generic, &priv->perm_hw_address }, + { NM_DEVICE_ETHERNET_SPEED, _nm_object_demarshal_generic, &priv->speed }, + { NM_DEVICE_ETHERNET_CARRIER, _nm_object_demarshal_generic, &priv->carrier }, { NULL }, }; @@ -230,6 +260,9 @@ finalize (GObject *object) if (priv->hw_address) g_free (priv->hw_address); + if (priv->perm_hw_address) + g_free (priv->perm_hw_address); + G_OBJECT_CLASS (nm_device_ethernet_parent_class)->finalize (object); } @@ -245,6 +278,9 @@ get_property (GObject *object, case PROP_HW_ADDRESS: g_value_set_string (value, nm_device_ethernet_get_hw_address (device)); break; + case PROP_PERM_HW_ADDRESS: + g_value_set_string (value, nm_device_ethernet_get_permanent_hw_address (device)); + break; case PROP_SPEED: g_value_set_uint (value, nm_device_ethernet_get_speed (device)); break; @@ -275,13 +311,26 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *device_class) /** * NMDeviceEthernet:hw-address: * - * The hardware (MAC) address of the device. + * The active hardware (MAC) address of the device. **/ g_object_class_install_property (object_class, PROP_HW_ADDRESS, g_param_spec_string (NM_DEVICE_ETHERNET_HW_ADDRESS, - "MAC Address", - "Hardware MAC address", + "Active MAC Address", + "Currently set hardware MAC address", + NULL, + G_PARAM_READABLE)); + + /** + * NMDeviceEthernet:perm-hw-address: + * + * The permanent hardware (MAC) address of the device. + **/ + g_object_class_install_property + (object_class, PROP_PERM_HW_ADDRESS, + g_param_spec_string (NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, + "Permanent MAC Address", + "Permanent hardware MAC address", NULL, G_PARAM_READABLE)); diff --git a/libnm-glib/nm-device-ethernet.h b/libnm-glib/nm-device-ethernet.h index 565e3e7e05..305ca022e8 100644 --- a/libnm-glib/nm-device-ethernet.h +++ b/libnm-glib/nm-device-ethernet.h @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. */ #ifndef NM_DEVICE_ETHERNET_H @@ -36,6 +36,7 @@ G_BEGIN_DECLS #define NM_DEVICE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) #define NM_DEVICE_ETHERNET_HW_ADDRESS "hw-address" +#define NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS "perm-hw-address" #define NM_DEVICE_ETHERNET_SPEED "speed" #define NM_DEVICE_ETHERNET_CARRIER "carrier" @@ -60,6 +61,7 @@ GType nm_device_ethernet_get_type (void); GObject *nm_device_ethernet_new (DBusGConnection *connection, const char *path); const char * nm_device_ethernet_get_hw_address (NMDeviceEthernet *device); +const char * nm_device_ethernet_get_permanent_hw_address (NMDeviceEthernet *device); guint32 nm_device_ethernet_get_speed (NMDeviceEthernet *device); gboolean nm_device_ethernet_get_carrier (NMDeviceEthernet *device); diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c index 1729c8aae9..3d17023950 100644 --- a/libnm-glib/nm-device-wifi.c +++ b/libnm-glib/nm-device-wifi.c @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. */ #include @@ -45,6 +45,7 @@ typedef struct { DBusGProxy *proxy; char *hw_address; + char *perm_hw_address; NM80211Mode mode; guint32 rate; NMAccessPoint *active_ap; @@ -58,6 +59,7 @@ typedef struct { enum { PROP_0, PROP_HW_ADDRESS, + PROP_PERM_HW_ADDRESS, PROP_MODE, PROP_BITRATE, PROP_ACTIVE_ACCESS_POINT, @@ -67,6 +69,7 @@ enum { }; #define DBUS_PROP_HW_ADDRESS "HwAddress" +#define DBUS_PROP_PERM_HW_ADDRESS "PermHwAddress" #define DBUS_PROP_MODE "Mode" #define DBUS_PROP_BITRATE "Bitrate" #define DBUS_PROP_ACTIVE_ACCESS_POINT "ActiveAccessPoint" @@ -106,9 +109,9 @@ nm_device_wifi_new (DBusGConnection *connection, const char *path) * nm_device_wifi_get_hw_address: * @device: a #NMDeviceWifi * - * Gets the hardware (MAC) address of the #NMDeviceWifi + * Gets the actual hardware (MAC) address of the #NMDeviceWifi * - * Returns: the hardware address. This is the internal string used by the + * Returns: the actual hardware address. This is the internal string used by the * device, and must not be modified. **/ const char * @@ -128,6 +131,32 @@ nm_device_wifi_get_hw_address (NMDeviceWifi *device) return priv->hw_address; } +/** + * nm_device_wifi_get_permanent_hw_address: + * @device: a #NMDeviceWifi + * + * Gets the permanent hardware (MAC) address of the #NMDeviceWifi + * + * Returns: the permanent hardware address. This is the internal string used by the + * device, and must not be modified. + **/ +const char * +nm_device_wifi_get_permanent_hw_address (NMDeviceWifi *device) +{ + NMDeviceWifiPrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL); + + priv = NM_DEVICE_WIFI_GET_PRIVATE (device); + if (!priv->perm_hw_address) { + priv->perm_hw_address = _nm_object_get_string_property (NM_OBJECT (device), + NM_DBUS_INTERFACE_DEVICE_WIRELESS, + DBUS_PROP_PERM_HW_ADDRESS); + } + + return priv->perm_hw_address; +} + /** * nm_device_wifi_get_mode: * @device: a #NMDeviceWifi @@ -464,6 +493,9 @@ get_property (GObject *object, case PROP_HW_ADDRESS: g_value_set_string (value, nm_device_wifi_get_hw_address (self)); break; + case PROP_PERM_HW_ADDRESS: + g_value_set_string (value, nm_device_wifi_get_permanent_hw_address (self)); + break; case PROP_MODE: g_value_set_uint (value, nm_device_wifi_get_mode (self)); break; @@ -554,11 +586,12 @@ register_for_property_changed (NMDeviceWifi *device) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); const NMPropertiesChangedInfo property_changed_info[] = { - { NM_DEVICE_WIFI_HW_ADDRESS, _nm_object_demarshal_generic, &priv->hw_address }, - { NM_DEVICE_WIFI_MODE, _nm_object_demarshal_generic, &priv->mode }, - { NM_DEVICE_WIFI_BITRATE, _nm_object_demarshal_generic, &priv->rate }, - { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, demarshal_active_ap, &priv->active_ap }, - { NM_DEVICE_WIFI_CAPABILITIES, _nm_object_demarshal_generic, &priv->wireless_caps }, + { NM_DEVICE_WIFI_HW_ADDRESS, _nm_object_demarshal_generic, &priv->hw_address }, + { NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, _nm_object_demarshal_generic, &priv->perm_hw_address }, + { NM_DEVICE_WIFI_MODE, _nm_object_demarshal_generic, &priv->mode }, + { NM_DEVICE_WIFI_BITRATE, _nm_object_demarshal_generic, &priv->rate }, + { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, demarshal_active_ap, &priv->active_ap }, + { NM_DEVICE_WIFI_CAPABILITIES, _nm_object_demarshal_generic, &priv->wireless_caps }, { NULL }, }; @@ -638,6 +671,9 @@ finalize (GObject *object) if (priv->hw_address) g_free (priv->hw_address); + if (priv->perm_hw_address) + g_free (priv->perm_hw_address); + G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -664,8 +700,21 @@ nm_device_wifi_class_init (NMDeviceWifiClass *device_class) g_object_class_install_property (object_class, PROP_HW_ADDRESS, g_param_spec_string (NM_DEVICE_WIFI_HW_ADDRESS, - "MAC Address", - "Hardware MAC address", + "Active MAC Address", + "Currently set hardware MAC address", + NULL, + G_PARAM_READABLE)); + + /** + * NMDeviceWifi:perm-hw-address: + * + * The hardware (MAC) address of the device. + **/ + g_object_class_install_property + (object_class, PROP_PERM_HW_ADDRESS, + g_param_spec_string (NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, + "Permanent MAC Address", + "Permanent hardware MAC address", NULL, G_PARAM_READABLE)); diff --git a/libnm-glib/nm-device-wifi.h b/libnm-glib/nm-device-wifi.h index 9152ab29db..21f3558af3 100644 --- a/libnm-glib/nm-device-wifi.h +++ b/libnm-glib/nm-device-wifi.h @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. */ #ifndef NM_DEVICE_WIFI_H @@ -37,6 +37,7 @@ G_BEGIN_DECLS #define NM_DEVICE_WIFI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass)) #define NM_DEVICE_WIFI_HW_ADDRESS "hw-address" +#define NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS "perm-hw-address" #define NM_DEVICE_WIFI_MODE "mode" #define NM_DEVICE_WIFI_BITRATE "bitrate" #define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point" @@ -67,6 +68,7 @@ GType nm_device_wifi_get_type (void); GObject *nm_device_wifi_new (DBusGConnection *connection, const char *path); const char * nm_device_wifi_get_hw_address (NMDeviceWifi *device); +const char * nm_device_wifi_get_permanent_hw_address (NMDeviceWifi *device); NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *device); guint32 nm_device_wifi_get_bitrate (NMDeviceWifi *device); guint32 nm_device_wifi_get_capabilities (NMDeviceWifi *device); diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index 3233d4067b..327693e4de 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -59,7 +59,7 @@ libnm_util_la_SOURCES= \ libnm_util_la_LIBADD = $(GLIB_LIBS) $(DBUS_LIBS) $(UUID_LIBS) libnm_util_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-util.ver \ - -version-info "5:0:4" + -version-info "6:0:5" if WITH_GNUTLS libnm_util_la_SOURCES += crypto_gnutls.c diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index 2c4919c16c..3983cd7c1b 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -288,6 +288,7 @@ global: nm_setting_wired_get_duplex; nm_setting_wired_get_auto_negotiate; nm_setting_wired_get_mac_address; + nm_setting_wired_get_cloned_mac_address; nm_setting_wired_get_mtu; nm_setting_wireless_ap_security_compatible; nm_setting_wireless_error_get_type; @@ -302,6 +303,7 @@ global: nm_setting_wireless_get_rate; nm_setting_wireless_get_tx_power; nm_setting_wireless_get_mac_address; + nm_setting_wireless_get_cloned_mac_address; nm_setting_wireless_get_mtu; nm_setting_wireless_get_security; nm_setting_wireless_add_seen_bssid; diff --git a/libnm-util/nm-setting-wired.c b/libnm-util/nm-setting-wired.c index 2f25243318..0f01832b50 100644 --- a/libnm-util/nm-setting-wired.c +++ b/libnm-util/nm-setting-wired.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -73,7 +73,8 @@ typedef struct { guint32 speed; char *duplex; gboolean auto_negotiate; - GByteArray *mac_address; + GByteArray *device_mac_address; + GByteArray *cloned_mac_address; guint32 mtu; } NMSettingWiredPrivate; @@ -84,6 +85,7 @@ enum { PROP_DUPLEX, PROP_AUTO_NEGOTIATE, PROP_MAC_ADDRESS, + PROP_CLONED_MAC_ADDRESS, PROP_MTU, LAST_PROP @@ -132,7 +134,15 @@ nm_setting_wired_get_mac_address (NMSettingWired *setting) { g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL); - return NM_SETTING_WIRED_GET_PRIVATE (setting)->mac_address; + return NM_SETTING_WIRED_GET_PRIVATE (setting)->device_mac_address; +} + +const GByteArray * +nm_setting_wired_get_cloned_mac_address (NMSettingWired *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL); + + return NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address; } guint32 @@ -166,7 +176,7 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } - if (priv->mac_address && priv->mac_address->len != ETH_ALEN) { + if (priv->device_mac_address && priv->device_mac_address->len != ETH_ALEN) { g_set_error (error, NM_SETTING_WIRED_ERROR, NM_SETTING_WIRED_ERROR_INVALID_PROPERTY, @@ -174,6 +184,14 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } + if (priv->cloned_mac_address && priv->cloned_mac_address->len != ETH_ALEN) { + g_set_error (error, + NM_SETTING_WIRED_ERROR, + NM_SETTING_WIRED_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRED_CLONED_MAC_ADDRESS); + return FALSE; + } + return TRUE; } @@ -191,8 +209,11 @@ finalize (GObject *object) g_free (priv->port); g_free (priv->duplex); - if (priv->mac_address) - g_byte_array_free (priv->mac_address, TRUE); + if (priv->device_mac_address) + g_byte_array_free (priv->device_mac_address, TRUE); + + if (priv->cloned_mac_address) + g_byte_array_free (priv->cloned_mac_address, TRUE); G_OBJECT_CLASS (nm_setting_wired_parent_class)->finalize (object); } @@ -219,9 +240,14 @@ set_property (GObject *object, guint prop_id, priv->auto_negotiate = g_value_get_boolean (value); break; case PROP_MAC_ADDRESS: - if (priv->mac_address) - g_byte_array_free (priv->mac_address, TRUE); - priv->mac_address = g_value_dup_boxed (value); + if (priv->device_mac_address) + g_byte_array_free (priv->device_mac_address, TRUE); + priv->device_mac_address = g_value_dup_boxed (value); + break; + case PROP_CLONED_MAC_ADDRESS: + if (priv->cloned_mac_address) + g_byte_array_free (priv->cloned_mac_address, TRUE); + priv->cloned_mac_address = g_value_dup_boxed (value); break; case PROP_MTU: priv->mtu = g_value_get_uint (value); @@ -254,6 +280,9 @@ get_property (GObject *object, guint prop_id, case PROP_MAC_ADDRESS: g_value_set_boxed (value, nm_setting_wired_get_mac_address (setting)); break; + case PROP_CLONED_MAC_ADDRESS: + g_value_set_boxed (value, nm_setting_wired_get_cloned_mac_address (setting)); + break; case PROP_MTU: g_value_set_uint (value, nm_setting_wired_get_mtu (setting)); break; @@ -351,20 +380,36 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class) * NMSettingWired:mac-address: * * If specified, this connection will only apply to the ethernet device - * whose MAC address matches. This property does not change the MAC address - * of the device (known as MAC spoofing). + * whose permanent MAC address matches. This property does not change the MAC address + * of the device (i.e. MAC spoofing). **/ g_object_class_install_property (object_class, PROP_MAC_ADDRESS, _nm_param_spec_specialized (NM_SETTING_WIRED_MAC_ADDRESS, - "MAC Address", + "Device MAC Address", "If specified, this connection will only apply to " - "the ethernet device whose MAC address matches. " + "the ethernet device whose permanent MAC address matches. " "This property does not change the MAC address " - "of the device (known as MAC spoofing).", + "of the device (i.e. MAC spoofing).", DBUS_TYPE_G_UCHAR_ARRAY, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** + * NMSettingWired:cloned-mac-address: + * + * If specified, request that the device use this MAC address instead of its + * permanent MAC address. This is known as MAC cloning or spoofing. + **/ + g_object_class_install_property + (object_class, PROP_CLONED_MAC_ADDRESS, + _nm_param_spec_specialized (NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + "Cloned MAC Address", + "If specified, request that the device use " + "this MAC address instead of its permanent MAC address. " + "This is known as MAC cloning or spoofing.", + DBUS_TYPE_G_UCHAR_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingWired:mtu: * diff --git a/libnm-util/nm-setting-wired.h b/libnm-util/nm-setting-wired.h index 44127347f2..a3f9ac86d9 100644 --- a/libnm-util/nm-setting-wired.h +++ b/libnm-util/nm-setting-wired.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -57,6 +57,7 @@ GQuark nm_setting_wired_error_quark (void); #define NM_SETTING_WIRED_DUPLEX "duplex" #define NM_SETTING_WIRED_AUTO_NEGOTIATE "auto-negotiate" #define NM_SETTING_WIRED_MAC_ADDRESS "mac-address" +#define NM_SETTING_WIRED_CLONED_MAC_ADDRESS "cloned-mac-address" #define NM_SETTING_WIRED_MTU "mtu" typedef struct { @@ -81,6 +82,7 @@ guint32 nm_setting_wired_get_speed (NMSettingWired *setting); const char *nm_setting_wired_get_duplex (NMSettingWired *setting); gboolean nm_setting_wired_get_auto_negotiate (NMSettingWired *setting); const GByteArray *nm_setting_wired_get_mac_address (NMSettingWired *setting); +const GByteArray *nm_setting_wired_get_cloned_mac_address (NMSettingWired *setting); guint32 nm_setting_wired_get_mtu (NMSettingWired *setting); G_END_DECLS diff --git a/libnm-util/nm-setting-wireless.c b/libnm-util/nm-setting-wireless.c index 44d010f7ac..99af8f2a34 100644 --- a/libnm-util/nm-setting-wireless.c +++ b/libnm-util/nm-setting-wireless.c @@ -86,7 +86,8 @@ typedef struct { GByteArray *bssid; guint32 rate; guint32 tx_power; - GByteArray *mac_address; + GByteArray *device_mac_address; + GByteArray *cloned_mac_address; guint32 mtu; GSList *seen_bssids; char *security; @@ -102,6 +103,7 @@ enum { PROP_RATE, PROP_TX_POWER, PROP_MAC_ADDRESS, + PROP_CLONED_MAC_ADDRESS, PROP_MTU, PROP_SEEN_BSSIDS, PROP_SEC, @@ -353,7 +355,15 @@ nm_setting_wireless_get_mac_address (NMSettingWireless *setting) { g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NULL); - return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->mac_address; + return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->device_mac_address; +} + +const GByteArray * +nm_setting_wireless_get_cloned_mac_address (NMSettingWireless *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NULL); + + return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->cloned_mac_address; } guint32 @@ -497,7 +507,7 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } - if (priv->mac_address && priv->mac_address->len != ETH_ALEN) { + if (priv->device_mac_address && priv->device_mac_address->len != ETH_ALEN) { g_set_error (error, NM_SETTING_WIRELESS_ERROR, NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY, @@ -505,6 +515,14 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } + if (priv->cloned_mac_address && priv->cloned_mac_address->len != ETH_ALEN) { + g_set_error (error, + NM_SETTING_WIRELESS_ERROR, + NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY, + NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS); + return FALSE; + } + for (iter = priv->seen_bssids; iter; iter = iter->next) { struct ether_addr addr; @@ -548,8 +566,10 @@ finalize (GObject *object) g_byte_array_free (priv->ssid, TRUE); if (priv->bssid) g_byte_array_free (priv->bssid, TRUE); - if (priv->mac_address) - g_byte_array_free (priv->mac_address, TRUE); + if (priv->device_mac_address) + g_byte_array_free (priv->device_mac_address, TRUE); + if (priv->cloned_mac_address) + g_byte_array_free (priv->cloned_mac_address, TRUE); nm_utils_slist_free (priv->seen_bssids, g_free); @@ -591,9 +611,14 @@ set_property (GObject *object, guint prop_id, priv->tx_power = g_value_get_uint (value); break; case PROP_MAC_ADDRESS: - if (priv->mac_address) - g_byte_array_free (priv->mac_address, TRUE); - priv->mac_address = g_value_dup_boxed (value); + if (priv->device_mac_address) + g_byte_array_free (priv->device_mac_address, TRUE); + priv->device_mac_address = g_value_dup_boxed (value); + break; + case PROP_CLONED_MAC_ADDRESS: + if (priv->cloned_mac_address) + g_byte_array_free (priv->cloned_mac_address, TRUE); + priv->cloned_mac_address = g_value_dup_boxed (value); break; case PROP_MTU: priv->mtu = g_value_get_uint (value); @@ -643,6 +668,9 @@ get_property (GObject *object, guint prop_id, case PROP_MAC_ADDRESS: g_value_set_boxed (value, nm_setting_wireless_get_mac_address (setting)); break; + case PROP_CLONED_MAC_ADDRESS: + g_value_set_boxed (value, nm_setting_wireless_get_cloned_mac_address (setting)); + break; case PROP_MTU: g_value_set_uint (value, nm_setting_wireless_get_mtu (setting)); break; @@ -809,20 +837,36 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class) * NMSettingWireless:mac-address: * * If specified, this connection will only apply to the WiFi device - * whose MAC address matches. This property does not change the MAC address - * of the device (known as MAC spoofing). + * whose permanent MAC address matches. This property does not change the MAC address + * of the device (i.e. MAC spoofing). **/ g_object_class_install_property (object_class, PROP_MAC_ADDRESS, _nm_param_spec_specialized (NM_SETTING_WIRELESS_MAC_ADDRESS, - "MAC Address", + "Device MAC Address", "If specified, this connection will only apply to " - "the WiFi device whose MAC address matches. " + "the WiFi device whose permanent MAC address matches. " "This property does not change the MAC address " - "of the device (known as MAC spoofing).", + "of the device (i.e. MAC spoofing).", DBUS_TYPE_G_UCHAR_ARRAY, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** + * NMSettingWireless:cloned-mac-address: + * + * If specified, request that the Wifi device use this MAC address instead of its + * permanent MAC address. This is known as MAC cloning or spoofing. + **/ + g_object_class_install_property + (object_class, PROP_CLONED_MAC_ADDRESS, + _nm_param_spec_specialized (NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, + "Spoof MAC Address", + "If specified, request that the WiFi device use " + "this MAC address instead of its permanent MAC address. " + "This is known as MAC cloning or spoofing.", + DBUS_TYPE_G_UCHAR_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + /** * NMSettingWireless:seen-bssids: * diff --git a/libnm-util/nm-setting-wireless.h b/libnm-util/nm-setting-wireless.h index da2ea5b6b0..2216a246af 100644 --- a/libnm-util/nm-setting-wireless.h +++ b/libnm-util/nm-setting-wireless.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -63,6 +63,7 @@ GQuark nm_setting_wireless_error_quark (void); #define NM_SETTING_WIRELESS_RATE "rate" #define NM_SETTING_WIRELESS_TX_POWER "tx-power" #define NM_SETTING_WIRELESS_MAC_ADDRESS "mac-address" +#define NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS "cloned-mac-address" #define NM_SETTING_WIRELESS_MTU "mtu" #define NM_SETTING_WIRELESS_SEEN_BSSIDS "seen-bssids" #define NM_SETTING_WIRELESS_SEC "security" @@ -93,6 +94,7 @@ const GByteArray *nm_setting_wireless_get_bssid (NMSettingWireless guint32 nm_setting_wireless_get_rate (NMSettingWireless *setting); guint32 nm_setting_wireless_get_tx_power (NMSettingWireless *setting); const GByteArray *nm_setting_wireless_get_mac_address (NMSettingWireless *setting); +const GByteArray *nm_setting_wireless_get_cloned_mac_address (NMSettingWireless *setting); guint32 nm_setting_wireless_get_mtu (NMSettingWireless *setting); const char *nm_setting_wireless_get_security (NMSettingWireless *setting); diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 4333d0f5d4..8a22b6b9bb 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -102,10 +102,11 @@ typedef struct Supplicant { } Supplicant; typedef struct { - gboolean disposed; + gboolean disposed; - struct ether_addr hw_addr; - gboolean carrier; + struct ether_addr hw_addr; /* Currently set MAC address */ + struct ether_addr perm_hw_addr; /* Permanent MAC address */ + gboolean carrier; NMNetlinkMonitor * monitor; gulong link_connected_id; @@ -131,6 +132,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, PROP_HW_ADDRESS, + PROP_PERM_HW_ADDRESS, PROP_SPEED, PROP_CARRIER, @@ -455,6 +457,21 @@ nm_device_ethernet_get_address (NMDeviceEthernet *self, struct ether_addr *addr) memcpy (addr, &(NM_DEVICE_ETHERNET_GET_PRIVATE (self)->hw_addr), sizeof (struct ether_addr)); } +/* + * nm_device_ethernet_get_permanent_address + * + * Get a device's permanent hardware address + * + */ +void +nm_device_ethernet_get_permanent_address (NMDeviceEthernet *self, struct ether_addr *addr) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (addr != NULL); + + memcpy (addr, &(NM_DEVICE_ETHERNET_GET_PRIVATE (self)->perm_hw_addr), sizeof (struct ether_addr)); +} + /* Returns speed in Mb/s */ static guint32 nm_device_ethernet_get_speed (NMDeviceEthernet *self) @@ -527,11 +544,50 @@ out: close (fd); } +static void +real_obtain_permanent_hw_address (NMDevice *dev) +{ + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + struct ifreq req; + struct ethtool_perm_addr *epaddr = NULL; + int fd; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + nm_log_warn (LOGD_HW, "couldn't open control socket."); + return; + } + + /* Get permanent MAC address */ + memset (&req, 0, sizeof (struct ifreq)); + strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); + epaddr = (struct ethtool_perm_addr *) g_malloc0 (sizeof(struct ethtool_perm_addr) + ETH_ALEN); + epaddr->cmd = ETHTOOL_GPERMADDR; + epaddr->size = ETH_ALEN; + req.ifr_data = epaddr; + errno = 0; + if (ioctl (fd, SIOCETHTOOL, &req) < 0) { + nm_log_err (LOGD_HW | LOGD_ETHER, "SIOCETHTOOL failed: %d; unable to get permanent MAC address for %s", + errno, nm_device_get_iface (dev)); + goto out; + } + + if (memcmp (&priv->perm_hw_addr, epaddr->data, sizeof (struct ether_addr))) { + memcpy (&priv->perm_hw_addr, epaddr->data, sizeof (struct ether_addr)); + g_object_notify (G_OBJECT (dev), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS); + } + +out: + g_free (epaddr); + close (fd); +} + static guint32 real_get_generic_capabilities (NMDevice *dev) { - NMDeviceEthernet * self = NM_DEVICE_ETHERNET (dev); - guint32 caps = NM_DEVICE_CAP_NONE; + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); + guint32 caps = NM_DEVICE_CAP_NONE; /* cipsec devices are also explicitly unsupported at this time */ if (strstr (nm_device_get_iface (dev), "cipsec")) @@ -1218,6 +1274,45 @@ supplicant_interface_init (NMDeviceEthernet *self) return TRUE; } +static NMActStageReturn +real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) +{ + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + NMActRequest *req; + NMSettingWired *s_wired; + const GByteArray *cloned_mac; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + s_wired = NM_SETTING_WIRED (device_get_setting (dev, NM_TYPE_SETTING_WIRED)); + g_assert (s_wired); + + cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); + if (cloned_mac) { + char *mac_str = NULL; + + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2], + cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]); + real_hw_take_down (dev); + if (nm_system_device_set_mac (nm_device_get_iface (dev), (struct ether_addr *) cloned_mac->data)) { + /* MAC address succesfully spoofed on interface, set it to hw_addr too */ + memcpy (priv->hw_addr.ether_addr_octet, cloned_mac->data, ETH_ALEN); + nm_log_info (LOGD_DEVICE | LOGD_ETHER, "cloned MAC %s set to %s", mac_str, nm_device_get_iface (dev)); + } else { + nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "failed to set cloned MAC %s to %s", mac_str, nm_device_get_iface (dev)); + } + real_hw_bring_up (dev, NULL); + g_free (mac_str); + } + + return ret; +} + static NMActStageReturn nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason) { @@ -1447,6 +1542,7 @@ static void real_deactivate_quickly (NMDevice *device) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); + char *mac_str = NULL; if (priv->pending_ip4_config) { g_object_unref (priv->pending_ip4_config); @@ -1459,6 +1555,22 @@ real_deactivate_quickly (NMDevice *device) } supplicant_interface_release (NM_DEVICE_ETHERNET (device)); + + /* Set permanent MAC address back to the interface */ + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", + priv->perm_hw_addr.ether_addr_octet[0], priv->perm_hw_addr.ether_addr_octet[1], priv->perm_hw_addr.ether_addr_octet[2], + priv->perm_hw_addr.ether_addr_octet[3], priv->perm_hw_addr.ether_addr_octet[4], priv->perm_hw_addr.ether_addr_octet[5]); + real_hw_take_down (device); + if (nm_system_device_set_mac (nm_device_get_iface (device), &priv->perm_hw_addr)) { + /* MAC address succesfully spoofed on interface, set it to hw_addr too */ + memcpy (priv->hw_addr.ether_addr_octet, &priv->perm_hw_addr, ETH_ALEN); + nm_log_info (LOGD_DEVICE | LOGD_ETHER, "permanent MAC address %s set back to %s", mac_str, nm_device_get_iface (device)); + } else { + nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "failed to set permanent MAC address %s back to %s", mac_str, nm_device_get_iface (device)); + } + real_hw_bring_up (device, NULL); + + g_free (mac_str); } static gboolean @@ -1501,7 +1613,7 @@ real_check_connection_compatible (NMDevice *device, const GByteArray *mac; mac = nm_setting_wired_get_mac_address (s_wired); - if (mac && memcmp (mac->data, &(priv->hw_addr.ether_addr_octet), ETH_ALEN)) { + if (mac && memcmp (mac->data, &(priv->perm_hw_addr.ether_addr_octet), ETH_ALEN)) { g_set_error (error, NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INCOMPATIBLE, "The connection's MAC address did not match this device."); @@ -1521,7 +1633,7 @@ spec_match_list (NMDevice *device, const GSList *specs) char *hwaddr; gboolean matched; - nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (device), ðer); + nm_device_ethernet_get_permanent_address (NM_DEVICE_ETHERNET (device), ðer); hwaddr = nm_ether_ntop (ðer); matched = nm_match_spec_hwaddr (specs, hwaddr); g_free (hwaddr); @@ -1543,7 +1655,7 @@ wired_match_config (NMDevice *self, NMConnection *connection) /* MAC address check */ s_ether = nm_setting_wired_get_mac_address (s_wired); if (s_ether) { - nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (self), ðer); + nm_device_ethernet_get_permanent_address (NM_DEVICE_ETHERNET (self), ðer); if (memcmp (s_ether->data, ether.ether_addr_octet, ETH_ALEN)) return FALSE; @@ -1770,6 +1882,10 @@ get_property (GObject *object, guint prop_id, nm_device_ethernet_get_address (self, &hw_addr); g_value_take_string (value, nm_ether_ntop (&hw_addr)); break; + case PROP_PERM_HW_ADDRESS: + nm_device_ethernet_get_permanent_address (self, &hw_addr); + g_value_take_string (value, nm_ether_ntop (&hw_addr)); + break; case PROP_SPEED: g_value_set_uint (value, nm_device_ethernet_get_speed (self)); break; @@ -1816,11 +1932,13 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->take_down = real_take_down; parent_class->can_interrupt_activation = real_can_interrupt_activation; parent_class->update_hw_address = real_update_hw_address; + parent_class->obtain_permanent_hw_address = real_obtain_permanent_hw_address; parent_class->get_best_auto_connection = real_get_best_auto_connection; parent_class->is_available = real_is_available; parent_class->connection_secrets_updated = real_connection_secrets_updated; parent_class->check_connection_compatible = real_check_connection_compatible; + parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; parent_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; @@ -1832,8 +1950,16 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) g_object_class_install_property (object_class, PROP_HW_ADDRESS, g_param_spec_string (NM_DEVICE_ETHERNET_HW_ADDRESS, - "MAC Address", - "Hardware MAC address", + "Active MAC Address", + "Currently set hardware MAC address", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_PERM_HW_ADDRESS, + g_param_spec_string (NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, + "Permanent MAC Address", + "Permanent hardware MAC address", NULL, G_PARAM_READABLE)); diff --git a/src/nm-device-ethernet.h b/src/nm-device-ethernet.h index 7bb3db0086..243fbedb29 100644 --- a/src/nm-device-ethernet.h +++ b/src/nm-device-ethernet.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2010 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -37,6 +37,7 @@ G_BEGIN_DECLS #define NM_DEVICE_ETHERNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) #define NM_DEVICE_ETHERNET_HW_ADDRESS "hw-address" +#define NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS "perm-hw-address" #define NM_DEVICE_ETHERNET_SPEED "speed" #define NM_DEVICE_ETHERNET_CARRIER "carrier" @@ -62,6 +63,9 @@ NMDevice *nm_device_ethernet_new (const char *udi, void nm_device_ethernet_get_address (NMDeviceEthernet *dev, struct ether_addr *addr); +void nm_device_ethernet_get_permanent_address (NMDeviceEthernet *dev, + struct ether_addr *addr); + G_END_DECLS #endif /* NM_DEVICE_ETHERNET_H */ diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 134e4f4449..729dc0690d 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include "nm-glib-compat.h" #include "nm-device.h" @@ -78,6 +81,7 @@ G_DEFINE_TYPE_EXTENDED (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE, 0, enum { PROP_0, PROP_HW_ADDRESS, + PROP_PERM_HW_ADDRESS, PROP_MODE, PROP_BITRATE, PROP_ACTIVE_ACCESS_POINT, @@ -142,7 +146,9 @@ typedef struct Supplicant { struct _NMDeviceWifiPrivate { gboolean disposed; - struct ether_addr hw_addr; + struct ether_addr hw_addr; /* Currently set MAC address */ + struct ether_addr perm_hw_addr; /* Permanent MAC address */ + gboolean perm_hw_addr_is_set; /* Legacy rfkill for ipw2x00; will be fixed with 2.6.33 kernel */ char * ipw_rfkill_path; @@ -1129,6 +1135,7 @@ real_deactivate_quickly (NMDevice *dev) NMDeviceWifi *self = NM_DEVICE_WIFI (dev); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMAccessPoint *orig_ap = nm_device_wifi_get_activation_ap (self); + char *mac_str = NULL; cleanup_association_attempt (self, TRUE); @@ -1148,6 +1155,22 @@ real_deactivate_quickly (NMDevice *dev) priv->ap_list = g_slist_remove (priv->ap_list, orig_ap); g_object_unref (orig_ap); } + + /* Set permanent MAC address back to the interface */ + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", + priv->perm_hw_addr.ether_addr_octet[0], priv->perm_hw_addr.ether_addr_octet[1], priv->perm_hw_addr.ether_addr_octet[2], + priv->perm_hw_addr.ether_addr_octet[3], priv->perm_hw_addr.ether_addr_octet[4], priv->perm_hw_addr.ether_addr_octet[5]); + real_hw_take_down (dev); + if (nm_system_device_set_mac (nm_device_get_iface (dev), &priv->perm_hw_addr)) { + /* MAC address succesfully spoofed on interface, set it to hw_addr too */ + memcpy (priv->hw_addr.ether_addr_octet, &priv->perm_hw_addr, ETH_ALEN); + nm_log_info (LOGD_DEVICE | LOGD_ETHER, "permanent MAC address %s set back to %s", mac_str, nm_device_get_iface (dev)); + } else { + nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "failed to set permanent MAC address %s back to %s", mac_str, nm_device_get_iface (dev)); + } + real_hw_bring_up (dev, NULL); + + g_free (mac_str); } static void @@ -1190,7 +1213,7 @@ real_check_connection_compatible (NMDevice *device, } mac = nm_setting_wireless_get_mac_address (s_wireless); - if (mac && memcmp (mac->data, &(priv->hw_addr.ether_addr_octet), ETH_ALEN)) { + if (mac && memcmp (mac->data, &(priv->perm_hw_addr.ether_addr_octet), ETH_ALEN)) { g_set_error (error, NM_WIFI_ERROR, NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, "The connection's MAC address did not match this device."); @@ -1308,6 +1331,25 @@ nm_device_wifi_get_address (NMDeviceWifi *self, memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr)); } +/* + * nm_device_wifi_get_permanent_address + * + * Get a device's permanent hardware address + * + */ +void +nm_device_wifi_get_permanent_address (NMDeviceWifi *self, + struct ether_addr *addr) +{ + NMDeviceWifiPrivate *priv; + + g_return_if_fail (self != NULL); + g_return_if_fail (addr != NULL); + + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + memcpy (addr, &(priv->perm_hw_addr), sizeof (struct ether_addr)); +} + static void nm_device_wifi_ap_list_print (NMDeviceWifi *self) { @@ -2949,6 +2991,51 @@ out: close (fd); } +static void +real_obtain_permanent_hw_address (NMDevice *dev) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI (dev); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + struct ifreq req; + struct ethtool_perm_addr *epaddr = NULL; + int fd; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + nm_log_err (LOGD_HW, "could not open control socket."); + return; + } + + /* Get permanent MAC address */ + memset (&req, 0, sizeof (struct ifreq)); + strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); + epaddr = (struct ethtool_perm_addr *) g_malloc0 (sizeof(struct ethtool_perm_addr) + ETH_ALEN); + epaddr->cmd = ETHTOOL_GPERMADDR; + epaddr->size = ETH_ALEN; + req.ifr_data = (void *) epaddr; + errno = 0; + if (ioctl (fd, SIOCETHTOOL, &req) < 0) { + nm_log_err (LOGD_HW | LOGD_ETHER, "SIOCETHTOOL failed: %d; unable to get permanent MAC address for %s", + errno, nm_device_get_iface (dev)); + + nm_log_warn (LOGD_HW | LOGD_ETHER, "Using current address as permanent address for %s", + nm_device_get_iface (dev)); + memcpy (&priv->perm_hw_addr, &priv->hw_addr, sizeof (struct ether_addr)); + g_object_notify (G_OBJECT (dev), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS); + + goto out; + } + + if (memcmp (&priv->perm_hw_addr, epaddr->data, sizeof (struct ether_addr))) { + memcpy (&priv->perm_hw_addr, epaddr->data, sizeof (struct ether_addr)); + g_object_notify (G_OBJECT (dev), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS); + } + +out: + g_free (epaddr); + close (fd); +} + static NMActStageReturn real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) @@ -2958,8 +3045,38 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) NMAccessPoint *ap = NULL; NMActRequest *req; NMConnection *connection; + NMSettingWireless *s_wireless; + const GByteArray *cloned_mac; GSList *iter; + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + connection = nm_act_request_get_connection (req); + g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + /* Set spoof MAC to the interface */ + s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); + g_assert (s_wireless); + + cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); + if (cloned_mac) { + char *mac_str = NULL; + + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2], + cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]); + real_hw_take_down (dev); + if (nm_system_device_set_mac (nm_device_get_iface (dev), (struct ether_addr *) cloned_mac->data)) { + /* MAC address succesfully spoofed on interface, set it to hw_addr too */ + memcpy (priv->hw_addr.ether_addr_octet, cloned_mac->data, ETH_ALEN); + nm_log_info (LOGD_DEVICE | LOGD_ETHER, "cloned MAC %s set to %s", mac_str, nm_device_get_iface (dev)); + } else { + nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "failed to set cloned MAC %s to %s", mac_str, nm_device_get_iface (dev)); + } + real_hw_bring_up (dev, NULL); + g_free (mac_str); + } + /* If the user is trying to connect to an AP that NM doesn't yet know about * (hidden network or something), create an fake AP from the security * settings in the connection to use until the AP is recognized from the @@ -2969,12 +3086,6 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) if (ap) goto done; - req = nm_device_get_act_request (NM_DEVICE (self)); - g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_connection (req); - g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); - /* Find a compatible AP in the scan list */ for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { NMAccessPoint *candidate = NM_AP (iter->data); @@ -3430,7 +3541,7 @@ spec_match_list (NMDevice *device, const GSList *specs) char *hwaddr; gboolean matched; - nm_device_wifi_get_address (NM_DEVICE_WIFI (device), ðer); + nm_device_wifi_get_permanent_address (NM_DEVICE_WIFI (device), ðer); hwaddr = nm_ether_ntop (ðer); matched = nm_match_spec_hwaddr (specs, hwaddr); g_free (hwaddr); @@ -3696,6 +3807,10 @@ get_property (GObject *object, guint prop_id, nm_device_wifi_get_address (device, &hw_addr); g_value_take_string (value, nm_ether_ntop (&hw_addr)); break; + case PROP_PERM_HW_ADDRESS: + nm_device_wifi_get_permanent_address (device, &hw_addr); + g_value_take_string (value, nm_ether_ntop (&hw_addr)); + break; case PROP_MODE: g_value_set_uint (value, nm_device_wifi_get_mode (device)); break; @@ -3763,6 +3878,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->bring_up = real_bring_up; parent_class->take_down = real_take_down; parent_class->update_hw_address = real_update_hw_address; + parent_class->obtain_permanent_hw_address = real_obtain_permanent_hw_address; parent_class->get_best_auto_connection = real_get_best_auto_connection; parent_class->is_available = real_is_available; parent_class->connection_secrets_updated = real_connection_secrets_updated; @@ -3783,8 +3899,15 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) /* Properties */ g_object_class_install_property (object_class, PROP_HW_ADDRESS, g_param_spec_string (NM_DEVICE_WIFI_HW_ADDRESS, - "MAC Address", - "Hardware MAC address", + "Active MAC Address", + "Currently set hardware MAC address", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_PERM_HW_ADDRESS, + g_param_spec_string (NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, + "Permanent MAC Address", + "Permanent hardware MAC address", NULL, G_PARAM_READABLE)); diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h index 11ac885735..d8b8522858 100644 --- a/src/nm-device-wifi.h +++ b/src/nm-device-wifi.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2010 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -43,6 +43,7 @@ G_BEGIN_DECLS #define NM_DEVICE_WIFI_HW_ADDRESS "hw-address" +#define NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS "perm-hw-address" #define NM_DEVICE_WIFI_MODE "mode" #define NM_DEVICE_WIFI_BITRATE "bitrate" #define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point" @@ -85,18 +86,17 @@ NMDevice *nm_device_wifi_new (const char *udi, const char *iface, const char *driver); -void nm_device_wifi_get_address (NMDeviceWifi *dev, - struct ether_addr *addr); +void nm_device_wifi_get_address (NMDeviceWifi *dev, struct ether_addr *addr); -void nm_device_wifi_get_bssid (NMDeviceWifi *dev, - struct ether_addr *bssid); +void nm_device_wifi_get_permanent_address (NMDeviceWifi *dev, struct ether_addr *addr); -const GByteArray * nm_device_wifi_get_ssid (NMDeviceWifi *self); +void nm_device_wifi_get_bssid (NMDeviceWifi *dev, struct ether_addr *bssid); -gboolean nm_device_wifi_set_mode (NMDeviceWifi *self, - const NM80211Mode mode); +const GByteArray * nm_device_wifi_get_ssid (NMDeviceWifi *self); -NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *self); +gboolean nm_device_wifi_set_mode (NMDeviceWifi *self, const NM80211Mode mode); + +NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *self); NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self); diff --git a/src/nm-device.c b/src/nm-device.c index 01874c5fde..9981f9b44c 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -283,6 +283,9 @@ constructor (GType type, if (NM_DEVICE_GET_CLASS (dev)->update_hw_address) NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev); + if (NM_DEVICE_GET_CLASS (dev)->obtain_permanent_hw_address) + NM_DEVICE_GET_CLASS (dev)->obtain_permanent_hw_address (dev); + priv->dhcp_manager = nm_dhcp_manager_get (); update_accept_ra_save (dev); diff --git a/src/nm-device.h b/src/nm-device.h index 202f392413..a2e0749598 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2010 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -72,6 +72,7 @@ typedef struct { void (*take_down) (NMDevice *self); void (* update_hw_address) (NMDevice *self); + void (* obtain_permanent_hw_address) (NMDevice *self); guint32 (* get_type_capabilities) (NMDevice *self); guint32 (* get_generic_capabilities) (NMDevice *self); diff --git a/src/nm-system.c b/src/nm-system.c index 35aa36a111..3e490933f3 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -772,6 +772,48 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu) return success; } +gboolean +nm_system_device_set_mac (const char *iface, const struct ether_addr *mac) +{ + struct rtnl_link *old; + struct rtnl_link *new; + gboolean success = FALSE; + struct nl_handle *nlh; + int iface_idx; + struct nl_addr *addr = NULL; + + g_return_val_if_fail (iface != NULL, FALSE); + g_return_val_if_fail (mac != NULL, FALSE); + + new = rtnl_link_alloc (); + if (!new) + return FALSE; + + iface_idx = nm_netlink_iface_to_index (iface); + old = nm_netlink_index_to_rtnl_link (iface_idx); + if (old) { + addr = nl_addr_build (AF_LLC, (void *) mac, ETH_ALEN); + if (!addr) { + char *mac_str; + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->ether_addr_octet[0], mac->ether_addr_octet[1], mac->ether_addr_octet[2], + mac->ether_addr_octet[3], mac->ether_addr_octet[4], mac->ether_addr_octet[5]); + nm_log_err (LOGD_DEVICE, "(%s): could not allocate memory for MAC address (%s)", iface, mac_str); + g_free (mac_str); + return FALSE; + } + rtnl_link_set_addr (new, addr); + nlh = nm_netlink_get_default_handle (); + if (nlh) { + rtnl_link_change (nlh, old, new, 0); + success = TRUE; + } + rtnl_link_put (old); + } + + rtnl_link_put (new); + return success; +} + static struct rtnl_route * add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss) { diff --git a/src/nm-system.h b/src/nm-system.h index 2eee01417d..29455cb4bf 100644 --- a/src/nm-system.h +++ b/src/nm-system.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2004 - 2008 Red Hat, Inc. + * Copyright (C) 2004 - 2010 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. */ @@ -25,6 +25,8 @@ #include #include +#include + #include #include "nm-device.h" #include "nm-ip4-config.h" @@ -80,5 +82,6 @@ gboolean nm_system_device_is_up (NMDevice *device); gboolean nm_system_device_is_up_with_iface (const char *iface); gboolean nm_system_device_set_mtu (const char *iface, guint32 mtu); +gboolean nm_system_device_set_mac (const char *iface, const struct ether_addr *mac); #endif diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index 1c7e8eb6c7..01ac32d8ae 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -185,7 +185,7 @@ make_connection_setting (const char *file, } static gboolean -read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) +read_mac_address (shvarFile *ifcfg, const char *key, GByteArray **array, GError **error) { char *value = NULL; struct ether_addr *mac; @@ -196,7 +196,7 @@ read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) g_return_val_if_fail (error != NULL, FALSE); g_return_val_if_fail (*error == NULL, FALSE); - value = svGetValue (ifcfg, "HWADDR", FALSE); + value = svGetValue (ifcfg, key, FALSE); if (!value || !strlen (value)) { g_free (value); return TRUE; @@ -206,7 +206,7 @@ read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) if (!mac) { g_free (value); g_set_error (error, ifcfg_plugin_error_quark (), 0, - "The MAC address '%s' was invalid.", value); + "%s: the MAC address '%s' was invalid.", key, value); return FALSE; } @@ -294,7 +294,7 @@ fill_ip4_setting_from_ibft (shvarFile *ifcfg, goto done; } - if (!read_mac_address (ifcfg, &ifcfg_mac, error)) + if (!read_mac_address (ifcfg, "HWADDR", &ifcfg_mac, error)) goto done; /* Ensure we got a MAC */ if (!ifcfg_mac) { @@ -2655,7 +2655,7 @@ make_wireless_setting (shvarFile *ifcfg, s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); - if (read_mac_address (ifcfg, &array, error)) { + if (read_mac_address (ifcfg, "HWADDR", &array, error)) { if (array) { g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, array, NULL); @@ -2678,6 +2678,14 @@ make_wireless_setting (shvarFile *ifcfg, return NULL; } + array = NULL; + if (read_mac_address (ifcfg, "MACADDR", &array, error)) { + if (array) { + g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL); + g_byte_array_free (array, TRUE); + } + } + value = svGetValue (ifcfg, "ESSID", TRUE); if (value) { gsize ssid_len = 0, value_len = strlen (value); @@ -2945,7 +2953,7 @@ make_wired_setting (shvarFile *ifcfg, g_free (value); } - if (read_mac_address (ifcfg, &mac, error)) { + if (read_mac_address (ifcfg, "HWADDR", &mac, error)) { if (mac) { g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL); @@ -2968,6 +2976,14 @@ make_wired_setting (shvarFile *ifcfg, s_wired = NULL; } + mac = NULL; + if (read_mac_address (ifcfg, "MACADDR", &mac, error)) { + if (mac) { + g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL); + g_byte_array_free (mac, TRUE); + } + } + value = svGetValue (ifcfg, "KEY_MGMT", FALSE); if (value) { if (!strcmp (value, "IEEE8021X")) { diff --git a/system-settings/plugins/ifcfg-rh/writer.c b/system-settings/plugins/ifcfg-rh/writer.c index 2d206c7354..dd75193e91 100644 --- a/system-settings/plugins/ifcfg-rh/writer.c +++ b/system-settings/plugins/ifcfg-rh/writer.c @@ -704,7 +704,7 @@ write_wireless_setting (NMConnection *connection, { NMSettingWireless *s_wireless; char *tmp, *tmp2; - const GByteArray *ssid, *mac, *bssid; + const GByteArray *ssid, *device_mac, *cloned_mac, *bssid; const char *mode; char buf[33]; guint32 mtu, chan, i; @@ -718,15 +718,25 @@ write_wireless_setting (NMConnection *connection, } svSetValue (ifcfg, "HWADDR", NULL, FALSE); - mac = nm_setting_wireless_get_mac_address (s_wireless); - if (mac) { + device_mac = nm_setting_wireless_get_mac_address (s_wireless); + if (device_mac) { tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", - mac->data[0], mac->data[1], mac->data[2], - mac->data[3], mac->data[4], mac->data[5]); + device_mac->data[0], device_mac->data[1], device_mac->data[2], + device_mac->data[3], device_mac->data[4], device_mac->data[5]); svSetValue (ifcfg, "HWADDR", tmp, FALSE); g_free (tmp); } + svSetValue (ifcfg, "MACADDR", NULL, FALSE); + cloned_mac = nm_setting_wireless_get_cloned_mac_address (s_wireless); + if (cloned_mac) { + tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", + cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2], + cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]); + svSetValue (ifcfg, "MACADDR", tmp, FALSE); + g_free (tmp); + } + svSetValue (ifcfg, "MTU", NULL, FALSE); mtu = nm_setting_wireless_get_mtu (s_wireless); if (mtu) { @@ -823,7 +833,7 @@ static gboolean write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingWired *s_wired; - const GByteArray *mac; + const GByteArray *device_mac, *cloned_mac; char *tmp; guint32 mtu; @@ -834,15 +844,24 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) return FALSE; } - mac = nm_setting_wired_get_mac_address (s_wired); - if (mac) { + device_mac = nm_setting_wired_get_mac_address (s_wired); + if (device_mac) { tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", - mac->data[0], mac->data[1], mac->data[2], - mac->data[3], mac->data[4], mac->data[5]); + device_mac->data[0], device_mac->data[1], device_mac->data[2], + device_mac->data[3], device_mac->data[4], device_mac->data[5]); svSetValue (ifcfg, "HWADDR", tmp, FALSE); g_free (tmp); } + cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); + if (cloned_mac) { + tmp = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", + cloned_mac->data[0], cloned_mac->data[1], cloned_mac->data[2], + cloned_mac->data[3], cloned_mac->data[4], cloned_mac->data[5]); + svSetValue (ifcfg, "MACADDR", tmp, FALSE); + g_free (tmp); + } + svSetValue (ifcfg, "MTU", NULL, FALSE); mtu = nm_setting_wired_get_mtu (s_wired); if (mtu) { diff --git a/system-settings/plugins/keyfile/io/reader.c b/system-settings/plugins/keyfile/io/reader.c index 5582733f66..50c3efe850 100644 --- a/system-settings/plugins/keyfile/io/reader.c +++ b/system-settings/plugins/keyfile/io/reader.c @@ -773,10 +773,18 @@ static KeyParser key_parsers[] = { NM_SETTING_WIRED_MAC_ADDRESS, TRUE, mac_address_parser }, + { NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + TRUE, + mac_address_parser }, { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS, TRUE, mac_address_parser }, + { NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, + TRUE, + mac_address_parser }, { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_BSSID, TRUE, diff --git a/system-settings/plugins/keyfile/io/writer.c b/system-settings/plugins/keyfile/io/writer.c index 348fa515f4..7bba71e685 100644 --- a/system-settings/plugins/keyfile/io/writer.c +++ b/system-settings/plugins/keyfile/io/writer.c @@ -488,9 +488,15 @@ static KeyWriter key_writers[] = { { NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS, mac_address_writer }, + { NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + mac_address_writer }, { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS, mac_address_writer }, + { NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, + mac_address_writer }, { NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_BSSID, mac_address_writer },