diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2010-06-22 14:21:25 +0200 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2010-06-22 14:21:25 +0200 |
commit | 1b49f941a69af910b0e68530be7339e8053068e5 (patch) | |
tree | c3431684e271d7e8506aeed7485c27da5faa5051 | |
parent | a8e0c2637b3a439908d8996300abc9aba7c8d297 (diff) |
core: MAC address spoofing/cloning (rh #447827) (bgo #553771)
This commit implements MAC cloning feature in NetworkManager. To support that,
'PermHwAddress' property is added into *.Device.Wired and *.Device.Wireless
interfaces. The permanent MAC address is obtained when creating the device, and
is used for 'locking' connections to the device. If a cloned MAC is specified
in connection to be activated, the MAC is set to the interface in stage1. While
disconecting, the permanent MAC is set back to the interface.
28 files changed, 705 insertions, 128 deletions
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 @@ <property name="HwAddress" type="s" access="read"> <tp:docstring> - Hardware address of the device. + Active hardware address of the device. + </tp:docstring> + </property> + + <property name="PermHwAddress" type="s" access="read"> + <tp:docstring> + Permanent hardware address of the device. </tp:docstring> </property> 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 @@ <property name="HwAddress" type="s" access="read"> <tp:docstring> - The hardware address of the device. + The active hardware address of the device. </tp:docstring> </property> + + <property name="PermHwAddress" type="s" access="read"> + <tp:docstring> + The permanent hardware address of the device. + </tp:docstring> + </property> + <property name="Mode" type="u" access="read" tp:type="NM_802_11_MODE"> <tp:docstring> 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 * @@ -103,6 +106,32 @@ nm_device_ethernet_get_hw_address (NMDeviceEthernet *device) } /** + * 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 <string.h> @@ -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 * @@ -129,6 +132,32 @@ nm_device_wifi_get_hw_address (NMDeviceWifi *device) } /** + * 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,21 +380,37 @@ 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: * * If non-zero, only transmit packets of the specified size or smaller, 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,21 +837,37 @@ 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: * * A list of BSSIDs (each BSSID formatted as a MAC address like 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")) @@ -1219,6 +1275,45 @@ supplicant_interface_init (NMDeviceEthernet *self) } 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) { NMConnection *connection; @@ -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 <sys/wait.h> #include <signal.h> #include <unistd.h> +#include <linux/sockios.h> +#include <linux/ethtool.h> +#include <sys/ioctl.h> #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 <netlink/route/rtnl.h> #include <netlink/route/route.h> +#include <net/ethernet.h> + #include <glib.h> #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,11 +773,19 @@ 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, mac_address_parser }, 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,10 +488,16 @@ 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 }, { NM_SETTING_BLUETOOTH_SETTING_NAME, |