Mercurial > hg > dhcpcd
changeset 5042:dac9291f82f0 draft
DHCP6: Clean up old lease when we fail to confirm/rebind, etc
Also removed the TIMEOUT states which makes things easier to read.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Thu, 06 Feb 2020 12:58:43 +0000 |
| parents | c44b319ae036 |
| children | f51d310db3b7 |
| files | src/dhcp6.c src/dhcp6.h src/ipv6.c |
| diffstat | 3 files changed, 93 insertions(+), 153 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dhcp6.c Thu Feb 06 12:54:11 2020 +0000 +++ b/src/dhcp6.c Thu Feb 06 12:58:43 2020 +0000 @@ -174,6 +174,12 @@ static void dhcp6_failinform(void *); static void dhcp6_recvaddr(void *); +#ifdef SMALL +#define dhcp6_hasprefixdelegation(a) (0) +#else +static int dhcp6_hasprefixdelegation(struct interface *); +#endif + void dhcp6_printoptions(const struct dhcpcd_ctx *ctx, const struct dhcp_opt *opts, size_t opts_len) @@ -1580,11 +1586,12 @@ struct dhcp6_state *state; ifp = arg; + state = D6_STATE(ifp); #ifndef SMALL - dhcp6_delete_delegates(ifp); + if (state->reason == NULL || strcmp(state->reason, "TIMEOUT6") != 0) + dhcp6_delete_delegates(ifp); #endif loginfox("%s: soliciting a DHCPv6 lease", ifp->name); - state = D6_STATE(ifp); state->state = DH6S_DISCOVER; state->RTC = 0; state->IMD = SOL_MAX_DELAY; @@ -1636,7 +1643,22 @@ } static void -dhcp6_fail(struct interface *ifp) +dhcp6_leaseextend(struct interface *ifp) +{ + struct dhcp6_state *state = D6_STATE(ifp); + struct ipv6_addr *ia; + + logwarnx("%s: extending DHCPv6 lease", ifp->name); + TAILQ_FOREACH(ia, &state->addrs, next) { + ia->flags |= IPV6_AF_EXTENDED; + /* Set infinite lifetimes. */ + ia->prefix_pltime = ND6_INFINITE_LIFETIME; + ia->prefix_vltime = ND6_INFINITE_LIFETIME; + } +} + +static void +dhcp6_fail(struct interface* ifp) { struct dhcp6_state *state = D6_STATE(ifp); @@ -1647,36 +1669,36 @@ * mobile clients. * dhcpcd also has LASTLEASE_EXTEND to extend this lease past it's * expiry, but this is strictly not RFC compliant in any way or form. */ - if (state->new == NULL || - !(ifp->options->options & DHCPCD_LASTLEASE)) + if (state->new != NULL && + ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { + dhcp6_leaseextend(ifp); + dhcp6_bind(ifp, NULL, NULL); + } else { + dhcp6_freedrop_addrs(ifp, 1, NULL); #ifndef SMALL dhcp6_delete_delegates(ifp); #endif - if (state->state != DH6S_INFORM) - dhcp6_startdiscover(ifp); - return; + free(state->old); + state->old = state->new; + state->old_len = state->new_len; + state->new = NULL; + state->new_len = 0; + if (state->old != NULL) + script_runreason(ifp, "EXPIRE6"); + unlink(state->leasefile); } - switch (state->state) { - case DH6S_INFORM: - case DH6S_INFORMED: - state->state = DH6S_ITIMEDOUT; - break; - default: - state->state = DH6S_TIMEDOUT; - break; - } - - dhcp6_bind(ifp, NULL, NULL); - - switch (state->state) { - case DH6S_BOUND: - case DH6S_INFORMED: - break; - default: + if (ifp->options->options & DHCPCD_IA_FORCED || + ipv6nd_hasradhcp(ifp, true)) dhcp6_startdiscover(ifp); - break; + else if (ifp->options->options & DHCPCD_INFORM6 || + ipv6nd_hasradhcp(ifp, false)) + dhcp6_startinform(ifp); + else { + logwarnx("%s: no advertising IPv6 router wants DHCP",ifp->name); + state->state = DH6S_INIT; + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); } } @@ -1710,9 +1732,7 @@ dhcp6_fail(ifp); } -#ifdef SMALL -#define dhcp6_hasprefixdelegation(a) (0) -#else +#ifndef SMALL static void dhcp6_failrebind(void *arg) { @@ -1838,21 +1858,6 @@ } static void -dhcp6_leaseextend(struct interface *ifp) -{ - struct dhcp6_state *state = D6_STATE(ifp); - struct ipv6_addr *ia; - - logwarnx("%s: extending DHCPv6 lease", ifp->name); - TAILQ_FOREACH(ia, &state->addrs, next) { - ia->flags |= IPV6_AF_EXTENDED; - /* Set infinite lifetimes. */ - ia->prefix_pltime = ND6_INFINITE_LIFETIME; - ia->prefix_vltime = ND6_INFINITE_LIFETIME; - } -} - -static void dhcp6_startexpire(void *arg) { struct interface *ifp; @@ -1861,24 +1866,7 @@ eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp); logerrx("%s: DHCPv6 lease expired", ifp->name); - if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { - struct dhcp6_state *state = D6_STATE(ifp); - - dhcp6_leaseextend(ifp); - ipv6_addaddrs(&state->addrs); - } else { - dhcp6_freedrop_addrs(ifp, 1, NULL); -#ifndef SMALL - dhcp6_delete_delegates(ifp); -#endif - script_runreason(ifp, "EXPIRE6"); - } - if (!(ifp->options->options & DHCPCD_IPV6RS) || - ipv6nd_hasradhcp(ifp) || - dhcp6_hasprefixdelegation(ifp)) - dhcp6_startdiscover(ifp); - else - logwarnx("%s: no advertising IPv6 router wants DHCP",ifp->name); + dhcp6_fail(ifp); } static void @@ -2436,7 +2424,7 @@ if (ia->flags & IPV6_AF_REQUEST) { ia->prefix_vltime = ia->prefix_pltime = 0; eloop_q_timeout_delete(ia->iface->ctx->eloop, - 0, NULL, ia); + ELOOP_QUEUE_ALL, NULL, ia); continue; } TAILQ_REMOVE(addrs, ia, next); @@ -2969,7 +2957,7 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) { struct dhcp6_state *state = D6_STATE(ifp); - bool has_new = false; + bool timedout = (op == NULL), has_new = false, confirmed; struct ipv6_addr *ia; logfunc_t *lognewinfo; struct timespec now; @@ -2981,24 +2969,28 @@ } } lognewinfo = has_new ? loginfox : logdebugx; - if (op != NULL) + if (!timedout) { lognewinfo("%s: %s received from %s", ifp->name, op, sfrom); - - state->reason = NULL; - if (state->state != DH6S_ITIMEDOUT) - eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + /* If we delegated from an unconfirmed lease we MUST drop + * them now. Hopefully we have new delegations. */ + if (state->reason != NULL && + strcmp(state->reason, "TIMEOUT6") == 0) + dhcp6_delete_delegates(ifp); + state->reason = NULL; + } else + state->reason = "TIMEOUT6"; + + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + clock_gettime(CLOCK_MONOTONIC, &now); + switch(state->state) { case DH6S_INFORM: - if (state->reason == NULL) - state->reason = "INFORM6"; - /* FALLTHROUGH */ - case DH6S_ITIMEDOUT: { struct dhcp6_option *o; uint16_t ol; if (state->reason == NULL) - state->reason = "ITIMEDOUT"; + state->reason = "INFORM6"; o = dhcp6_findmoption(state->new, state->new_len, D6_OPTION_INFO_REFRESH_TIME, &ol); if (o == NULL || ol != sizeof(uint32_t)) @@ -3030,10 +3022,6 @@ case DH6S_CONFIRM: if (state->reason == NULL) state->reason = "REBOOT6"; - /* FALLTHROUGH */ - case DH6S_TIMEDOUT: - if (state->reason == NULL) - state->reason = "TIMEOUT6"; if (state->renew != 0) { bool all_expired = true; @@ -3079,11 +3067,20 @@ break; } - clock_gettime(CLOCK_MONOTONIC, &now); - if (state->state == DH6S_TIMEDOUT || state->state == DH6S_ITIMEDOUT) { + if (state->state != DH6S_CONFIRM && !timedout) { + state->acquired = now; + free(state->old); + state->old = state->new; + state->old_len = state->new_len; + state->new = state->recv; + state->new_len = state->recv_len; + state->recv = NULL; + state->recv_len = 0; + confirmed = false; + } else { + /* Reduce timers based on when we got the lease. */ uint32_t elapsed; - /* Reduce timers */ elapsed = (uint32_t)eloop_timespec_diff(&now, &state->acquired, NULL); if (state->renew && state->renew != ND6_INFINITE_LIFETIME) { @@ -3101,69 +3098,19 @@ if (state->expire && state->expire != ND6_INFINITE_LIFETIME) { if (state->expire > elapsed) state->expire -= elapsed; - else { - if (!(ifp->options->options & - DHCPCD_LASTLEASE_EXTEND)) - return; - state->expire = ND6_INFINITE_LIFETIME; - } + else + state->expire = 0; } - if (state->expire == ND6_INFINITE_LIFETIME && - ifp->options->options & DHCPCD_LASTLEASE_EXTEND) - dhcp6_leaseextend(ifp); - - /* Restart rebind or renew phases in a second. */ - if (state->expire != ND6_INFINITE_LIFETIME) { - if (state->rebind == 0 && - state->rebind != ND6_INFINITE_LIFETIME) - state->rebind = 1; - else if (state->renew == 0 && - state->renew != ND6_INFINITE_LIFETIME) - state->renew = 1; - } - } else - state->acquired = now; - - switch (state->state) { - case DH6S_CONFIRM: - case DH6S_TIMEDOUT: - case DH6S_ITIMEDOUT: - break; - default: - free(state->old); - state->old = state->new; - state->old_len = state->new_len; - state->new = state->recv; - state->new_len = state->recv_len; - state->recv = NULL; - state->recv_len = 0; - break; + confirmed = true; } if (ifp->ctx->options & DHCPCD_TEST) script_runreason(ifp, "TEST"); else { - bool timed_out; - - switch(state->state) { - case DH6S_TIMEDOUT: - case DH6S_ITIMEDOUT: - timed_out = true; - break; - default: - timed_out = false; - break; - } - - switch(state->state) { - case DH6S_INFORM: - case DH6S_ITIMEDOUT: + if (state->state == DH6S_INFORM) state->state = DH6S_INFORMED; - break; - default: + else state->state = DH6S_BOUND; - break; - } if (state->renew && state->renew != ND6_INFINITE_LIFETIME) eloop_timeout_add_sec(ifp->ctx->eloop, @@ -3176,12 +3123,10 @@ if (state->expire != ND6_INFINITE_LIFETIME) eloop_timeout_add_sec(ifp->ctx->eloop, state->expire, dhcp6_startexpire, ifp); - else if (timed_out) - eloop_timeout_add_sec(ifp->ctx->eloop, - state->expire, dhcp6_startdiscover, ifp); ipv6_addaddrs(&state->addrs); - dhcp6_deprecateaddrs(&state->addrs); + if (!timedout) + dhcp6_deprecateaddrs(&state->addrs); if (state->state == DH6S_INFORMED) lognewinfo("%s: refresh in %"PRIu32" seconds", @@ -3200,7 +3145,7 @@ lognewinfo("%s: expire in %"PRIu32" seconds", ifp->name, state->expire); rt_build(ifp->ctx, AF_INET6); - if (!timed_out) + if (!confirmed && !timedout) dhcp6_writelease(ifp); #ifndef SMALL dhcp6_delegate_prefix(ifp); @@ -3487,13 +3432,11 @@ memcpy(state->recv, r, len); state->recv_len = len; - switch (r->type) { - case DHCP6_ADVERTISE: - { + if (r->type == DHCP6_ADVERTISE) { struct ipv6_addr *ia; if (state->state == DH6S_REQUEST) /* rapid commit */ - break; + goto bind; TAILQ_FOREACH(ia, &state->addrs, next) { if (!(ia->flags & (IPV6_AF_STALE | IPV6_AF_REQUEST))) break; @@ -3506,13 +3449,11 @@ else loginfox("%s: ADV %s from %s", ifp->name, ia->saddr, sfrom); - if (ifp->ctx->options & DHCPCD_TEST) - break; dhcp6_startrequest(ifp); return; } - } - + +bind: dhcp6_bind(ifp, op, sfrom); }
--- a/src/dhcp6.h Thu Feb 06 12:54:11 2020 +0000 +++ b/src/dhcp6.h Thu Feb 06 12:58:43 2020 +0000 @@ -169,8 +169,6 @@ DH6S_RENEW_REQUESTED, DH6S_PROBE, DH6S_DELEGATED, - DH6S_TIMEDOUT, - DH6S_ITIMEDOUT, DH6S_RELEASE, DH6S_RELEASED };
--- a/src/ipv6.c Thu Feb 06 12:54:11 2020 +0000 +++ b/src/ipv6.c Thu Feb 06 12:58:43 2020 +0000 @@ -1528,9 +1528,10 @@ /* If adding a new DHCP / RA derived address, check current flags * from an existing address. */ ia = ipv6_iffindaddr(ifp, addr, 0); - if (ia != NULL) + if (ia != NULL) { addr_flags = ia->addr_flags; - else + flags |= IPV6_AF_ADDED; + } else addr_flags = IN6_IFF_TENTATIVE; ia = calloc(1, sizeof(*ia));
