From 2a94587232f5ac401cd8d2f13729836f731566f2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 20 May 2016 13:47:23 +0200 Subject: [PATCH] device: only set permanent hardware address once While a device is realized, we only want to read the permanent MAC address once. If that fails, we fallback to the current MAC address. Thus, we want the permanent address be stable until the device unrealizes. While we want to fallback to the current MAC address, in some cases the caller wants to know whether this was a "real" permanent MAC address as read via ethtool. For example, when matching an ethernet device against ethernet.mac-address property, the fake (current) address should not be used in such case. --- src/devices/nm-device-ethernet.c | 8 +-- src/devices/nm-device.c | 92 ++++++++++++++++++++----------- src/devices/nm-device.h | 3 +- src/devices/wifi/nm-device-wifi.c | 6 +- 4 files changed, 68 insertions(+), 41 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 7c03ae6ac5..f38798234a 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -408,7 +408,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!match_subchans (self, s_wired, &try_mac)) return FALSE; - perm_hw_addr = nm_device_get_permanent_hw_address (device); + perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE); mac = nm_setting_wired_get_mac_address (s_wired); if (perm_hw_addr) { if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) @@ -1405,7 +1405,7 @@ complete_connection (NMDevice *device, nm_connection_add_setting (connection, NM_SETTING (s_wired)); } - perm_hw_addr = nm_device_get_permanent_hw_address (device); + perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE); if (perm_hw_addr) { setting_mac = nm_setting_wired_get_mac_address (s_wired); if (setting_mac) { @@ -1502,7 +1502,7 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired = nm_connection_get_setting_wired (connection); - const char *perm_hw_addr = nm_device_get_permanent_hw_address (device); + const char *perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE); const char *mac = nm_device_get_hw_address (device); const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; GHashTableIter iter; @@ -1636,7 +1636,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (object))); + g_value_set_string (value, nm_device_get_permanent_hw_address ((NMDevice *) object, FALSE)); break; case PROP_SPEED: g_value_set_uint (value, priv->speed); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index a0a7e41581..6e5660be5c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -237,8 +237,9 @@ typedef struct _NMDevicePrivate { char * driver_version; char * firmware_version; RfKillType rfkill_type; - bool firmware_missing; - bool nm_plugin_missing; + bool firmware_missing:1; + bool nm_plugin_missing:1; + bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */ GHashTable * available_connections; char * hw_addr; guint hw_addr_len; @@ -11371,17 +11372,14 @@ void nm_device_update_hw_address (NMDevice *self) { NMDevicePrivate *priv; - int ifindex; const guint8 *hwaddr; gsize hwaddrlen = 0; - ifindex = nm_device_get_ifindex (self); - if (ifindex <= 0) + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->ifindex <= 0) return; - priv = NM_DEVICE_GET_PRIVATE (self); - - hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen); + hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &hwaddrlen); if ( priv->type == NM_DEVICE_TYPE_ETHERNET && hwaddr @@ -11433,29 +11431,49 @@ void nm_device_update_permanent_hw_address (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + size_t len = 0; + gboolean success_read; - if (priv->hw_addr_len) { - if (priv->ifindex > 0) { - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; - size_t len = 0; - gboolean success_read; - - success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len); - - if (success_read && len == priv->hw_addr_len) { - priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); - _LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s", - priv->hw_addr_perm); - } else { - /* Fall back to current address */ - _LOGD (LOGD_HW | LOGD_ETHER, "%s", - success_read - ? "unable to read permanent MAC address" - : "read HW addr length of permanent MAC address differs"); - priv->hw_addr_perm = g_strdup (priv->hw_addr); - } - } + if (priv->hw_addr_perm) { + /* the permanent hardware address is only read once and not + * re-read later. + * + * Except during unrealize/realize cycles, where we clear the permanent + * hardware address during unrealization. */ + return; } + + if (priv->ifindex <= 0) + return; + + if (!priv->hw_addr_len) { + nm_device_update_hw_address (self); + if (!priv->hw_addr_len) + return; + } + + success_read = nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len); + if (!success_read || len != priv->hw_addr_len) { + /* Fall back to current address. We use the fake address and keep it + * until the device unrealizes. + * + * In some cases it might be necessary to know whether this is a "real" or + * a temporary address (fake). */ + _LOGD (LOGD_HW | LOGD_ETHER, "hw-addr: %s (use current: %s)", + success_read + ? "unable to read permanent MAC address" + : "read HW addr length of permanent MAC address differs", + priv->hw_addr); + priv->hw_addr_perm_fake = TRUE; + priv->hw_addr_perm = g_strdup (priv->hw_addr); + return; + } + + priv->hw_addr_perm_fake = FALSE; + priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, len); + _LOGD (LOGD_DEVICE, "hw-addr: read permanent MAC address '%s'", + priv->hw_addr_perm); } static gboolean @@ -11529,7 +11547,7 @@ nm_device_hw_addr_set (NMDevice *self, const char *addr) priv = NM_DEVICE_GET_PRIVATE (self); if (!addr) { - addr = priv->hw_addr_perm; + addr = nm_device_get_permanent_hw_address (self, TRUE); if (!addr) return FALSE; } @@ -11546,18 +11564,26 @@ nm_device_hw_addr_reset (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); - addr = priv->hw_addr_initial; + addr = nm_device_get_initial_hw_address (self); if (!addr) return FALSE; return _hw_addr_set (self, addr, "reset"); } const char * -nm_device_get_permanent_hw_address (NMDevice *self) +nm_device_get_permanent_hw_address (NMDevice *self, gboolean fallback_fake) { + NMDevicePrivate *priv; + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->hw_addr_perm; + priv = NM_DEVICE_GET_PRIVATE (self); + if (!priv->hw_addr_perm) + return NULL; + if ( priv->hw_addr_perm_fake + && !fallback_fake) + return NULL; + return priv->hw_addr_perm; } const char * diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index b6e563c87f..bd8e64a9ab 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -353,7 +353,8 @@ guint32 nm_device_get_ip4_route_metric (NMDevice *dev); guint32 nm_device_get_ip6_route_metric (NMDevice *dev); const char * nm_device_get_hw_address (NMDevice *dev); -const char * nm_device_get_permanent_hw_address (NMDevice *dev); +const char * nm_device_get_permanent_hw_address (NMDevice *dev, + gboolean fallback_fake); const char * nm_device_get_initial_hw_address (NMDevice *dev); NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 4bdc6e8e2a..e126a98e82 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -570,7 +570,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_wireless) return FALSE; - perm_hw_addr = nm_device_get_permanent_hw_address (device); + perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE); mac = nm_setting_wireless_get_mac_address (s_wireless); if (perm_hw_addr) { if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) @@ -862,7 +862,7 @@ complete_connection (NMDevice *device, if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - perm_hw_addr = nm_device_get_permanent_hw_address (device); + perm_hw_addr = nm_device_get_permanent_hw_address (device, FALSE); if (perm_hw_addr) { setting_mac = nm_setting_wireless_get_mac_address (s_wifi); if (setting_mac) { @@ -2981,7 +2981,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (device))); + g_value_set_string (value, nm_device_get_permanent_hw_address ((NMDevice *) device, FALSE)); break; case PROP_MODE: g_value_set_uint (value, priv->mode);