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);