core: merge branch 'bg/device-zero-mac-fix-rh1288110'

Fix activation for ethernet devices that appear with a zero initial
MAC address.

https://bugzilla.redhat.com/show_bug.cgi?id=1288110
This commit is contained in:
Beniamino Galvani 2016-01-07 13:39:41 +01:00
commit 3b35bf0ad7
4 changed files with 77 additions and 47 deletions

View file

@ -1607,10 +1607,44 @@ link_changed (NMDevice *device, NMPlatformLink *info)
{
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
static const guint8 zero_hwaddr[ETH_ALEN];
const guint8 *hwaddr;
gsize hwaddrlen = 0;
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
if (!priv->subchan1 && info->initialized)
_update_s390_subchannels (self);
if (!nm_device_get_initial_hw_address (device)) {
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET,
nm_device_get_ifindex (self),
&hwaddrlen);
if (!nm_utils_hwaddr_matches (hwaddr, hwaddrlen, zero_hwaddr, ETH_ALEN)) {
_LOGD (LOGD_DEVICE, "device got a valid hw address");
nm_device_update_hw_address (self);
nm_device_update_initial_hw_address (self);
if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) {
/*
* If the device is UNAVAILABLE, any previous try to
* bring it up probably has failed because of the
* invalid hardware address; try again.
*/
nm_device_bring_up (self, TRUE, NULL);
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
}
}
}
}
static gboolean
is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
{
if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->is_available (device, flags))
return FALSE;
return !!nm_device_get_initial_hw_address (device);
}
static void
@ -1711,6 +1745,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
parent_class->update_connection = update_connection;
parent_class->carrier_changed = carrier_changed;
parent_class->link_changed = link_changed;
parent_class->is_available = is_available;
parent_class->state_changed = device_state_changed;

View file

@ -89,7 +89,6 @@ enum {
REMOVED,
RECHECK_AUTO_ACTIVATE,
RECHECK_ASSUME,
LINK_INITIALIZED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
@ -403,8 +402,6 @@ static void _set_state_full (NMDevice *self,
NMDeviceStateReason reason,
gboolean quitting);
static void nm_device_update_hw_address (NMDevice *self);
static gboolean queued_ip4_config_change (gpointer user_data);
static gboolean queued_ip6_config_change (gpointer user_data);
@ -1589,9 +1586,6 @@ device_link_changed (NMDevice *self)
}
}
if (just_initialized)
g_signal_emit (self, signals[LINK_INITIALIZED], 0);
device_recheck_slave_status (self, &info);
return G_SOURCE_REMOVE;
}
@ -1904,27 +1898,7 @@ setup_start (NMDevice *self, const NMPlatformLink *plink)
priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
nm_device_update_hw_address (self);
if (priv->hw_addr_len) {
priv->initial_hw_addr = g_strdup (priv->hw_addr);
_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr);
if (priv->ifindex > 0) {
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
size_t len = 0;
if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) {
g_warn_if_fail (len == priv->hw_addr_len);
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s",
priv->perm_hw_addr);
} else {
/* Fall back to current address */
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address");
priv->perm_hw_addr = g_strdup (priv->hw_addr);
}
}
}
nm_device_update_initial_hw_address (self);
/* Note: initial hardware address must be read before calling get_ignore_carrier() */
if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
@ -9883,19 +9857,24 @@ nm_device_get_hw_address (NMDevice *self)
return priv->hw_addr_len ? priv->hw_addr : NULL;
}
static void
void
nm_device_update_hw_address (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ifindex (self);
const guint8 *hwaddr;
gsize hwaddrlen = 0;
static const guint8 zero_hwaddr[ETH_ALEN];
if (ifindex <= 0)
return;
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen);
if ( priv->type == NM_DEVICE_TYPE_ETHERNET
&& nm_utils_hwaddr_matches (hwaddr, hwaddrlen, zero_hwaddr, sizeof (zero_hwaddr)))
hwaddrlen = 0;
if (hwaddrlen) {
priv->hw_addr_len = hwaddrlen;
if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
@ -9917,6 +9896,33 @@ nm_device_update_hw_address (NMDevice *self)
}
}
void
nm_device_update_initial_hw_address (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->hw_addr_len) {
priv->initial_hw_addr = g_strdup (priv->hw_addr);
_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr);
if (priv->ifindex > 0) {
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
size_t len = 0;
if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) {
g_warn_if_fail (len == priv->hw_addr_len);
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s",
priv->perm_hw_addr);
} else {
/* Fall back to current address */
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address");
priv->perm_hw_addr = g_strdup (priv->hw_addr);
}
}
}
}
gboolean
nm_device_set_hw_addr (NMDevice *self, const char *addr,
const char *detail, guint64 hw_log_domain)
@ -10897,13 +10903,6 @@ nm_device_class_init (NMDeviceClass *klass)
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[LINK_INITIALIZED] =
g_signal_new (NM_DEVICE_LINK_INITIALIZED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
NMDBUS_TYPE_DEVICE_SKELETON,
"Disconnect", impl_device_disconnect,

View file

@ -567,6 +567,9 @@ void nm_device_reapply_settings_immediately (NMDevice *self);
void nm_device_update_firewall_zone (NMDevice *self);
void nm_device_update_metered (NMDevice *self);
void nm_device_update_hw_address (NMDevice *self);
void nm_device_update_initial_hw_address (NMDevice *self);
G_END_DECLS
#endif /* NM_DEVICE_H */

View file

@ -721,6 +721,7 @@ manager_device_state_changed (NMDevice *device,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
switch (new_state) {
case NM_DEVICE_STATE_UNMANAGED:
@ -733,6 +734,10 @@ manager_device_state_changed (NMDevice *device,
default:
break;
}
if ( new_state == NM_DEVICE_STATE_UNAVAILABLE
|| new_state == NM_DEVICE_STATE_DISCONNECTED)
nm_settings_device_added (priv->settings, device);
}
static void device_has_pending_action_changed (NMDevice *device,
@ -859,14 +864,6 @@ device_removed_cb (NMDevice *device, gpointer user_data)
remove_device (NM_MANAGER (user_data), device, FALSE, TRUE);
}
static void
device_link_initialized_cb (NMDevice *device, gpointer user_data)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data);
nm_settings_device_added (priv->settings, device);
}
NMState
nm_manager_get_state (NMManager *manager)
{
@ -1830,10 +1827,6 @@ add_device (NMManager *self, NMDevice *device, GError **error)
G_CALLBACK (device_removed_cb),
self);
g_signal_connect (device, NM_DEVICE_LINK_INITIALIZED,
G_CALLBACK (device_link_initialized_cb),
self);
g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
G_CALLBACK (recheck_assume_connection_cb),
self);