summaryrefslogtreecommitdiff
path: root/src/core/nm-l3-ipv6ll.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/nm-l3-ipv6ll.c')
-rw-r--r--src/core/nm-l3-ipv6ll.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/src/core/nm-l3-ipv6ll.c b/src/core/nm-l3-ipv6ll.c
index 2e2a6a0a5a..9becd07caf 100644
--- a/src/core/nm-l3-ipv6ll.c
+++ b/src/core/nm-l3-ipv6ll.c
@@ -391,7 +391,7 @@ _pladdr_find_ll(NML3IPv6LL *self, gboolean *out_cur_addr_failed)
/*****************************************************************************/
static void
-_lladdr_handle_changed(NML3IPv6LL *self)
+_lladdr_handle_changed(NML3IPv6LL *self, gboolean force_commit)
{
const NML3ConfigData *l3cd;
gboolean changed = FALSE;
@@ -434,7 +434,7 @@ _lladdr_handle_changed(NML3IPv6LL *self)
self->l3cfg_commit_handle,
"ipv6ll");
- if (changed)
+ if (changed || force_commit)
nm_l3cfg_commit_on_idle_schedule(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO);
if (!self->emit_changed_idle_source) {
@@ -515,6 +515,7 @@ _check(NML3IPv6LL *self)
const NMPlatformIP6Address *pladdr;
char sbuf[INET6_ADDRSTRLEN];
gboolean cur_addr_failed;
+ gboolean restarted = FALSE;
struct in6_addr lladdr;
pladdr = _pladdr_find_ll(self, &cur_addr_failed);
@@ -526,14 +527,14 @@ _check(NML3IPv6LL *self)
if (_set_cur_lladdr_obj(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, pladdr)) {
_LOGT("changed: waiting for address %s to complete DAD",
nm_inet6_ntop(&self->cur_lladdr, sbuf));
- _lladdr_handle_changed(self);
+ _lladdr_handle_changed(self, FALSE);
}
return;
}
if (_set_cur_lladdr_obj(self, NM_L3_IPV6LL_STATE_READY, pladdr)) {
_LOGT("changed: address %s is ready", nm_inet6_ntop(&self->cur_lladdr, sbuf));
- _lladdr_handle_changed(self);
+ _lladdr_handle_changed(self, FALSE);
}
return;
}
@@ -543,11 +544,17 @@ _check(NML3IPv6LL *self)
* Prematurely abort DAD to generate a new address below. */
nm_assert(
NM_IN_SET(self->state, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, NM_L3_IPV6LL_STATE_READY));
- if (self->state == NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS)
- _LOGT("changed: address %s did not complete DAD",
- nm_inet6_ntop(&self->cur_lladdr, sbuf));
- else {
+
+ if (cur_addr_failed) {
+ /* On DAD failure, we always try to regenerate a new address. */
+ _LOGT("changed: address %s failed", nm_inet6_ntop(&self->cur_lladdr, sbuf));
+ } else {
_LOGT("changed: address %s is gone", nm_inet6_ntop(&self->cur_lladdr, sbuf));
+ /* When the address is removed, we always try to re-add it. */
+ nm_clear_g_source_inst(&self->wait_for_addr_source);
+ lladdr = self->cur_lladdr;
+ restarted = TRUE;
+ goto commit;
}
/* reset the state here, so that we are sure that the following
@@ -569,18 +576,19 @@ _check(NML3IPv6LL *self)
if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_FAILED, NULL)) {
_LOGW("changed: no IPv6 link local address to retry after Duplicate Address Detection "
"failures (back off)");
- _lladdr_handle_changed(self);
+ _lladdr_handle_changed(self, FALSE);
}
return;
}
+commit:
/* we give NML3Cfg 2 seconds to configure the address on the interface. We
* thus very soon expect to see this address configured (and kernel started DAD).
* If that does not happen within timeout, we assume that this address failed DAD. */
self->wait_for_addr_source = nm_g_timeout_add_source(2000, _wait_for_addr_timeout_cb, self);
- if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, &lladdr)) {
+ if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, &lladdr) || restarted) {
_LOGT("changed: starting DAD for address %s", nm_inet6_ntop(&self->cur_lladdr, sbuf));
- _lladdr_handle_changed(self);
+ _lladdr_handle_changed(self, restarted);
}
return;
}