summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2010-06-22 14:21:25 +0200
committerJiří Klimeš <jklimes@redhat.com>2010-06-22 14:21:25 +0200
commit1b49f941a69af910b0e68530be7339e8053068e5 (patch)
treec3431684e271d7e8506aeed7485c27da5faa5051
parenta8e0c2637b3a439908d8996300abc9aba7c8d297 (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.
-rw-r--r--cli/src/connections.c4
-rw-r--r--cli/src/settings.c58
-rw-r--r--introspection/nm-device-ethernet.xml8
-rw-r--r--introspection/nm-device-wifi.xml9
-rw-r--r--libnm-glib/Makefile.am2
-rw-r--r--libnm-glib/libnm-glib.ver2
-rw-r--r--libnm-glib/nm-device-ethernet.c69
-rw-r--r--libnm-glib/nm-device-ethernet.h4
-rw-r--r--libnm-glib/nm-device-wifi.c69
-rw-r--r--libnm-glib/nm-device-wifi.h4
-rw-r--r--libnm-util/Makefile.am2
-rw-r--r--libnm-util/libnm-util.ver2
-rw-r--r--libnm-util/nm-setting-wired.c73
-rw-r--r--libnm-util/nm-setting-wired.h4
-rw-r--r--libnm-util/nm-setting-wireless.c70
-rw-r--r--libnm-util/nm-setting-wireless.h4
-rw-r--r--src/nm-device-ethernet.c146
-rw-r--r--src/nm-device-ethernet.h6
-rw-r--r--src/nm-device-wifi.c145
-rw-r--r--src/nm-device-wifi.h18
-rw-r--r--src/nm-device.c3
-rw-r--r--src/nm-device.h3
-rw-r--r--src/nm-system.c42
-rw-r--r--src/nm-system.h5
-rw-r--r--system-settings/plugins/ifcfg-rh/reader.c28
-rw-r--r--system-settings/plugins/ifcfg-rh/writer.c39
-rw-r--r--system-settings/plugins/keyfile/io/reader.c8
-rw-r--r--system-settings/plugins/keyfile/io/writer.c6
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), &ether);
+ nm_device_ethernet_get_permanent_address (NM_DEVICE_ETHERNET (device), &ether);
hwaddr = nm_ether_ntop (&ether);
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), &ether);
+ nm_device_ethernet_get_permanent_address (NM_DEVICE_ETHERNET (self), &ether);
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), &ether);
+ nm_device_wifi_get_permanent_address (NM_DEVICE_WIFI (device), &ether);
hwaddr = nm_ether_ntop (&ether);
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,