diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index caed116f51..9f5ca4b2bb 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1208,6 +1208,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) { NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMUtilsIPv6IfaceId token_iid; gboolean ip_ifname_changed = FALSE; if (info->udi && g_strcmp0 (info->udi, priv->udi)) { @@ -1254,6 +1255,12 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) nm_device_enslave_slave (priv->master, self, NULL); } + if (priv->rdisc && nm_platform_link_get_ipv6_token (priv->ifindex, &token_iid)) { + _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); + if (nm_rdisc_set_iid (priv->rdisc, token_iid)) + nm_rdisc_start (priv->rdisc); + } + if (klass->link_changed) klass->link_changed (self, info); @@ -4244,11 +4251,12 @@ addrconf6_start_with_link_ready (NMDevice *self) g_assert (priv->rdisc); - if (!nm_device_get_ip_iface_identifier (self, &iid)) { + if (nm_platform_link_get_ipv6_token (priv->ifindex, &iid)) { + _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); + } else if (!nm_device_get_ip_iface_identifier (self, &iid)) { _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 cannot continue"); return FALSE; } - nm_rdisc_set_iid (priv->rdisc, iid); /* Apply any manual configuration before starting RA */ if (!ip6_config_merge_and_apply (self, TRUE, NULL)) @@ -4267,6 +4275,8 @@ addrconf6_start_with_link_ready (NMDevice *self) NM_RDISC_RA_TIMEOUT, G_CALLBACK (rdisc_ra_timeout), self); + + nm_rdisc_set_iid (priv->rdisc, iid); nm_rdisc_start (priv->rdisc); return TRUE; } diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c index 8729fa63df..58040c9d43 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/rdisc/nm-rdisc.c @@ -42,12 +42,38 @@ static guint signals[LAST_SIGNAL] = { 0 }; /******************************************************************/ -void +/** + * nm_rdisc_set_iid: + * @rdisc: the #NMRDisc + * @iid: the new interface ID + * + * Sets the "Modified EUI-64" interface ID to be used when generating + * IPv6 addresses using received prefixes. Identifiers are either generated + * from the hardware addresses or manually set by the operator with + * "ip token" command. + * + * Upon token change (or initial setting) all addresses generated using + * the old identifier are removed. The caller should ensure the addresses + * will be reset by soliciting router advertisements. + * + * Returns: %TRUE if the token was changed, %FALSE otherwise. + **/ +gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) { - g_return_if_fail (NM_IS_RDISC (rdisc)); + g_return_val_if_fail (NM_IS_RDISC (rdisc), FALSE); - rdisc->iid = iid; + if (rdisc->iid.id != iid.id) { + rdisc->iid = iid; + if (rdisc->addresses->len) { + debug ("(%s) IPv6 interface identifier changed, flushing addresses", rdisc->ifname); + g_array_remove_range (rdisc->addresses, 0, rdisc->addresses->len); + g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, NM_RDISC_CONFIG_ADDRESSES); + } + return TRUE; + } + + return FALSE; } void diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h index 2d83f0f020..8864c22f72 100644 --- a/src/rdisc/nm-rdisc.h +++ b/src/rdisc/nm-rdisc.h @@ -139,7 +139,7 @@ typedef struct { GType nm_rdisc_get_type (void); -void nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid); +gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid); void nm_rdisc_start (NMRDisc *rdisc); #endif /* __NETWORKMANAGER_RDISC_H__ */