"No Prefix Available"
};
+static void dhcp6_bind(struct interface *, const char *);
+static void dhcp6_failinform(void *);
+
void
dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
const struct dhcp_opt *opts, size_t opts_len)
ml = state->new_len;
}
TAILQ_FOREACH(ap, &state->addrs, next) {
+ if (ap->flags & IPV6_AF_STALE)
+ continue;
if (ap->prefix_vltime == 0 &&
!(ap->flags & IPV6_AF_REQUEST))
continue;
ia_na.t2 = 0;
COPYIN(ifo->ia[l].ia_type, &ia_na, sizeof(ia_na));
TAILQ_FOREACH(ap, &state->addrs, next) {
+ if (ap->flags & IPV6_AF_STALE)
+ continue;
if (ap->prefix_vltime == 0 &&
!(ap->flags & IPV6_AF_REQUEST))
continue;
state->state = DH6S_RENEW;
state->RTC = 0;
+ state->IMD = REN_MAX_DELAY;
state->IRT = REN_TIMEOUT;
state->MRT = REN_MAX_RT;
state->MRC = 0;
state->IMD = SOL_MAX_DELAY;
state->IRT = SOL_TIMEOUT;
state->MRT = state->sol_max_rt;
- state->MRC = 0;
+ state->MRC = SOL_MAX_RC;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
free(state->new);
state->new = NULL;
state->new_len = 0;
- dhcp6_freedrop_addrs(ifp, 0, NULL);
- unlink(state->leasefile);
-
- dhcp6_addrequestedaddrs(ifp);
-
if (dhcp6_makemessage(ifp) == -1)
logerr("%s: %s", __func__, ifp->name);
else
dhcp6_senddiscover(ifp);
}
+static void
+dhcp6_startinform(void *arg)
+{
+ struct interface *ifp;
+ struct dhcp6_state *state;
+
+ ifp = arg;
+ state = D6_STATE(ifp);
+ if (state->new == NULL || ifp->options->options & DHCPCD_DEBUG)
+ loginfox("%s: requesting DHCPv6 information", ifp->name);
+ state->state = DH6S_INFORM;
+ state->RTC = 0;
+ state->IMD = INF_MAX_DELAY;
+ state->IRT = INF_TIMEOUT;
+ state->MRT = state->inf_max_rt;
+ state->MRC = 0;
+
+ eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+ if (dhcp6_makemessage(ifp) == -1) {
+ logerr("%s: %s", __func__, ifp->name);
+ return;
+ }
+ dhcp6_sendinform(ifp);
+ /* RFC3315 18.1.2 says that if CONFIRM failed then the prior addresses
+ * SHOULD be used. The wording here is poor, because the addresses are
+ * merely one facet of the lease as a whole.
+ * This poor wording might explain the lack of similar text for INFORM
+ * in 18.1.5 because there are no addresses in the INFORM message. */
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ INF_MAX_RD, dhcp6_failinform, ifp);
+}
+
+static void
+dhcp6_fail(struct interface *ifp)
+{
+ struct dhcp6_state *state = D6_STATE(ifp);
+
+ /* RFC3315 18.1.2 says that prior addresses SHOULD be used on failure.
+ * RFC2131 3.2.3 says that MAY chose to use the prior address.
+ * Because dhcpcd was written first for RFC2131, we have the LASTLEASE
+ * option which defaults to off as that makes the most sense for
+ * 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))
+ {
+#ifndef SMALL
+ dhcp6_delete_delegates(ifp);
+#endif
+ if (state->state != DH6S_INFORM)
+ dhcp6_startdiscover(ifp);
+ return;
+ }
+
+ switch (state->state) {
+ case DH6S_INFORM:
+ case DH6S_INFORMED:
+ state->state = DH6S_ITIMEDOUT;
+ break;
+ default:
+ state->state = DH6S_TIMEDOUT;
+ break;
+ }
+
+ dhcp6_bind(ifp, NULL);
+
+ switch (state->state) {
+ case DH6S_BOUND:
+ case DH6S_INFORMED:
+ break;
+ default:
+ dhcp6_startdiscover(ifp);
+ break;
+ }
+}
+
static void
dhcp6_failconfirm(void *arg)
{
ifp = arg;
logerrx("%s: failed to confirm prior address", ifp->name);
- /* Section 18.1.2 says that we SHOULD use the last known
- * IP address(s) and lifetimes if we didn't get a reply.
- * I disagree with this. */
- dhcp6_startdiscover(ifp);
+ dhcp6_fail(ifp);
}
static void
ifp = arg;
logerrx("%s: failed to request address", ifp->name);
- /* Section 18.1.1 says that client local policy dictates
- * what happens if a REQUEST fails.
- * Of the possible scenarios listed, moving back to the
- * DISCOVER phase makes more sense for us. */
- dhcp6_startdiscover(ifp);
+ dhcp6_fail(ifp);
+}
+
+static void
+dhcp6_failinform(void *arg)
+{
+ struct interface *ifp;
+
+ ifp = arg;
+ logerrx("%s: failed to request information", ifp->name);
+ dhcp6_fail(ifp);
}
#ifdef SMALL
ifp = arg;
logerrx("%s: failed to rebind prior delegation", ifp->name);
- dhcp6_delete_delegates(ifp);
- /* Section 18.1.2 says that we SHOULD use the last known
- * IP address(s) and lifetimes if we didn't get a reply.
- * I disagree with this. */
- dhcp6_startdiscover(ifp);
+ dhcp6_fail(ifp);
}
static int
} else
#endif
{
+ state->IMD = REB_MAX_DELAY;
state->IRT = REB_TIMEOUT;
state->MRT = REB_MAX_RT;
}
state = D6_STATE(ifp);
state->state = DH6S_REQUEST;
state->RTC = 0;
+ state->IMD = 0;
state->IRT = REQ_TIMEOUT;
state->MRT = REQ_MAX_RT;
state->MRC = REQ_MAX_RC;
state->IMD = CNF_MAX_DELAY;
state->IRT = CNF_TIMEOUT;
state->MRT = CNF_MAX_RT;
- state->MRC = 0;
+ state->MRC = CNF_MAX_RC;
loginfox("%s: confirming prior DHCPv6 lease", ifp->name);
if (dhcp6_makemessage(ifp) == -1) {
}
static void
-dhcp6_startinform(void *arg)
+dhcp6_leaseextend(struct interface *ifp)
{
- struct interface *ifp;
- struct dhcp6_state *state;
-
- ifp = arg;
- state = D6_STATE(ifp);
- if (state->new == NULL || ifp->options->options & DHCPCD_DEBUG)
- loginfox("%s: requesting DHCPv6 information", ifp->name);
- state->state = DH6S_INFORM;
- state->RTC = 0;
- state->IMD = INF_MAX_DELAY;
- state->IRT = INF_TIMEOUT;
- state->MRT = state->inf_max_rt;
- state->MRC = 0;
+ struct dhcp6_state *state = D6_STATE(ifp);
+ struct ipv6_addr *ia;
- if (dhcp6_makemessage(ifp) == -1)
- logerr("%s: %s", __func__, ifp->name);
- else
- dhcp6_sendinform(ifp);
+ 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
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp);
logerrx("%s: DHCPv6 lease expired", ifp->name);
- dhcp6_freedrop_addrs(ifp, 1, NULL);
+ 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);
+ dhcp6_delete_delegates(ifp);
#endif
- script_runreason(ifp, "EXPIRE6");
- if (ipv6nd_hasradhcp(ifp) || dhcp6_hasprefixdelegation(ifp))
+ 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);
state->state = DH6S_RELEASE;
state->RTC = 0;
+ state->IMD = REL_MAX_DELAY;
state->IRT = REL_TIMEOUT;
- state->MRT = 0;
+ state->MRT = REL_MAX_RT;
/* MRC of REL_MAX_RC is optional in RFC 3315 18.1.6 */
#if 0
state->MRC = REL_MAX_RC;
} else {
if (!(a->flags & IPV6_AF_ONLINK))
a->flags |= IPV6_AF_ONLINK | IPV6_AF_NEW;
- a->flags &= ~IPV6_AF_STALE;
+ a->flags &= ~(IPV6_AF_STALE | IPV6_AF_EXTENDED);
}
a->acquired = *acquired;
a->prefix_pltime = ia.pltime;
a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
TAILQ_INIT(&a->pd_pfxs);
}
- a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
+ a->flags &= ~(IPV6_AF_STALE |
+ IPV6_AF_EXTENDED |
+ IPV6_AF_REQUEST);
if (a->prefix_vltime != ntohl(pdp.vltime))
a->flags |= IPV6_AF_NEW;
}
struct ipv6_addr *ia, *ian;
TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
- if (ia->flags & IPV6_AF_STALE) {
+ if (ia->flags & IPV6_AF_EXTENDED)
+ ;
+ else if (ia->flags & IPV6_AF_STALE) {
if (ia->prefix_vltime != 0)
logdebugx("%s: %s: became stale",
ia->iface->name, ia->saddr);
continue;
}
TAILQ_REMOVE(addrs, ia, next);
+ if (ia->flags & IPV6_AF_EXTENDED)
+ ipv6_deleteaddr(ia);
ipv6_freeaddr(ia);
}
}
struct stat st;
int fd;
struct dhcp6_message *lease;
- struct timespec acquired;
time_t now;
int retval;
bool fd_opened;
goto auth;
}
- clock_gettime(CLOCK_MONOTONIC, &acquired);
+ clock_gettime(CLOCK_MONOTONIC, &state->acquired);
if ((now = time(NULL)) == -1)
goto ex;
- acquired.tv_sec -= now - st.st_mtime;
+ state->acquired.tv_sec -= now - st.st_mtime;
/* Check to see if the lease is still valid */
fd = dhcp6_validatelease(ifp, state->new, state->new_len, NULL,
- &acquired);
+ &state->acquired);
if (fd == -1)
goto ex;
if (state->expire != ND6_INFINITE_LIFETIME &&
state->leasefile[0] != '\0')
{
- if ((time_t)state->expire < now - st.st_mtime) {
+ if ((time_t)state->expire < now - st.st_mtime &&
+ !(ifp->options->options & DHCPCD_LASTLEASE_EXTEND)) {
logdebugx("%s: discarding expired lease", ifp->name);
retval = 0;
goto ex;
}
#endif
+static void
+dhcp6_bind(struct interface *ifp, const char *op)
+{
+ struct dhcp6_state *state = D6_STATE(ifp);
+ bool has_new = false;
+ struct ipv6_addr *ia;
+ logfunc_t *lognewinfo;
+ struct timespec now;
+
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ if (ia->flags & IPV6_AF_NEW) {
+ has_new = true;
+ break;
+ }
+ }
+ lognewinfo = has_new ? loginfox : logdebugx;
+ if (op != NULL)
+ lognewinfo("%s: %s received from %s",
+ ifp->name, op, ifp->ctx->sfrom);
+
+ state->reason = NULL;
+ if (state->state != DH6S_ITIMEDOUT)
+ eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+ 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";
+ o = dhcp6_findmoption(state->new, state->new_len,
+ D6_OPTION_INFO_REFRESH_TIME, &ol);
+ if (o == NULL || ol != sizeof(uint32_t))
+ state->renew = IRT_DEFAULT;
+ else {
+ memcpy(&state->renew, o, ol);
+ state->renew = ntohl(state->renew);
+ if (state->renew < IRT_MINIMUM)
+ state->renew = IRT_MINIMUM;
+ }
+ state->rebind = 0;
+ state->expire = ND6_INFINITE_LIFETIME;
+ state->lowpl = ND6_INFINITE_LIFETIME;
+ }
+ break;
+
+ case DH6S_REQUEST:
+ if (state->reason == NULL)
+ state->reason = "BOUND6";
+ /* FALLTHROUGH */
+ case DH6S_RENEW:
+ if (state->reason == NULL)
+ state->reason = "RENEW6";
+ /* FALLTHROUGH */
+ case DH6S_REBIND:
+ if (state->reason == NULL)
+ state->reason = "REBIND6";
+ /* FALLTHROUGH */
+ case DH6S_CONFIRM:
+ if (state->reason == NULL)
+ state->reason = "REBOOT6";
+ case DH6S_TIMEDOUT:
+ if (state->reason == NULL)
+ state->reason = "TIMEOUT6";
+ if (state->renew != 0) {
+ bool all_expired = true;
+
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ loginfox("%s %d", ia->saddr, ia->flags);
+ if (ia->flags & IPV6_AF_STALE)
+ continue;
+ if (ia->prefix_vltime <= state->renew)
+ logwarnx(
+ "%s: %s will expire before renewal",
+ ifp->name, ia->saddr);
+ else
+ all_expired = false;
+ }
+ if (all_expired) {
+ /* All address's vltime happens at or before
+ * the configured T1 in the IA.
+ * This is a badly configured server and we
+ * have to use our own notion of what
+ * T1 and T2 should be as a result.
+ *
+ * Doing this violates RFC 3315 22.4:
+ * In a message sent by a server to a client,
+ * the client MUST use the values in the T1
+ * and T2 fields for the T1 and T2 parameters,
+ * unless those values in those fields are 0.
+ */
+ logwarnx("%s: ignoring T1 %"PRIu32
+ " to due address expiry",
+ ifp->name, state->renew);
+ state->renew = state->rebind = 0;
+ }
+ }
+ if (state->renew == 0 && state->lowpl != ND6_INFINITE_LIFETIME)
+ state->renew = (uint32_t)(state->lowpl * 0.5);
+ if (state->rebind == 0 && state->lowpl != ND6_INFINITE_LIFETIME)
+ state->rebind = (uint32_t)(state->lowpl * 0.8);
+ break;
+ default:
+ state->reason = "UNKNOWN6";
+ break;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (state->state == DH6S_TIMEDOUT || state->state == DH6S_ITIMEDOUT) {
+ struct timespec diff;
+
+ /* Reduce timers */
+ timespecsub(&now, &state->acquired, &diff);
+ if (state->renew && state->renew != ND6_INFINITE_LIFETIME) {
+ if (state->renew > diff.tv_sec)
+ state->renew -= diff.tv_sec;
+ else
+ state->renew = 0;
+ }
+ if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME) {
+ if (state->rebind > diff.tv_sec)
+ state->rebind -= diff.tv_sec;
+ else
+ state->rebind = 0;
+ }
+ if (state->expire && state->expire != ND6_INFINITE_LIFETIME) {
+ if (state->expire > diff.tv_sec)
+ state->expire -= diff.tv_sec;
+ else {
+ if (!(ifp->options->options &
+ DHCPCD_LASTLEASE_EXTEND))
+ return;
+ state->expire = ND6_INFINITE_LIFETIME;
+ }
+ }
+ 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;
+ }
+
+ 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:
+ state->state = DH6S_INFORMED;
+ break;
+ default:
+ state->state = DH6S_BOUND;
+ break;
+ }
+
+ if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ (time_t)state->renew,
+ state->state == DH6S_INFORMED ?
+ dhcp6_startinform : dhcp6_startrenew, ifp);
+ if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ (time_t)state->rebind, dhcp6_startrebind, ifp);
+ if (state->expire != ND6_INFINITE_LIFETIME)
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ (time_t)state->expire, dhcp6_startexpire, ifp);
+ else if (timed_out)
+ eloop_timeout_add_sec(ifp->ctx->eloop,
+ (time_t)state->expire, dhcp6_startdiscover, ifp);
+
+ ipv6_addaddrs(&state->addrs);
+ dhcp6_deprecateaddrs(&state->addrs);
+
+ if (state->state == DH6S_INFORMED)
+ lognewinfo("%s: refresh in %"PRIu32" seconds",
+ ifp->name, state->renew);
+ else if (state->renew || state->rebind)
+ lognewinfo("%s: renew in %"PRIu32", "
+ "rebind in %"PRIu32", "
+ "expire in %"PRIu32" seconds",
+ ifp->name,
+ state->renew, state->rebind, state->expire);
+ else if (state->expire == 0)
+ lognewinfo("%s: will expire", ifp->name);
+ else
+ lognewinfo("%s: expire in %"PRIu32" seconds",
+ ifp->name, state->expire);
+ if_initrt(ifp->ctx, AF_INET6);
+ rt_build(ifp->ctx, AF_INET6);
+ if (!timed_out)
+ dhcp6_writelease(ifp);
+#ifndef SMALL
+ dhcp6_delegate_prefix(ifp);
+#endif
+ dhcp6_script_try_run(ifp, 0);
+ }
+
+ if (ifp->ctx->options & DHCPCD_TEST ||
+ (ifp->options->options & DHCPCD_INFORM &&
+ !(ifp->ctx->options & DHCPCD_MASTER)))
+ {
+ eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
+ }
+}
+
/* ARGSUSED */
static void
dhcp6_handledata(void *arg)
const struct dhcp_opt *opt;
const struct if_options *ifo;
struct ipv6_addr *ap;
- bool valid_op, has_new;
- logfunc_t *lognewinfo;
+ bool valid_op;
#ifdef AUTH
uint8_t *auth;
uint16_t auth_len;
case DH6S_INFORM:
if (dhcp6_checkstatusok(ifp, r, NULL, len) == -1)
return;
- /* RFC4242 */
- o = dhcp6_findmoption(r, len,
- D6_OPTION_INFO_REFRESH_TIME, &ol);
- if (o == NULL || ol != sizeof(uint32_t))
- state->renew = IRT_DEFAULT;
- else {
- memcpy(&state->renew, o, ol);
- state->renew = ntohl(state->renew);
- if (state->renew < IRT_MINIMUM)
- state->renew = IRT_MINIMUM;
- }
break;
case DH6S_CONFIRM:
if (dhcp6_validatelease(ifp, r, len,
if (state->state == DH6S_REQUEST) /* rapid commit */
break;
TAILQ_FOREACH(ap, &state->addrs, next) {
- if (!(ap->flags & IPV6_AF_REQUEST))
+ if (!(ap->flags & (IPV6_AF_STALE | IPV6_AF_REQUEST)))
break;
}
if (ap == NULL)
return;
}
- has_new = false;
- TAILQ_FOREACH(ap, &state->addrs, next) {
- if (ap->flags & IPV6_AF_NEW) {
- has_new = true;
- break;
- }
- }
- lognewinfo = has_new ? loginfox : logdebugx;
- lognewinfo("%s: %s received from %s", ifp->name, op, ctx->sfrom);
-
- state->reason = NULL;
- eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
- switch(state->state) {
- case DH6S_INFORM:
- state->rebind = 0;
- state->expire = ND6_INFINITE_LIFETIME;
- state->lowpl = ND6_INFINITE_LIFETIME;
- state->reason = "INFORM6";
- break;
- case DH6S_REQUEST:
- if (state->reason == NULL)
- state->reason = "BOUND6";
- /* FALLTHROUGH */
- case DH6S_RENEW:
- if (state->reason == NULL)
- state->reason = "RENEW6";
- /* FALLTHROUGH */
- case DH6S_REBIND:
- if (state->reason == NULL)
- state->reason = "REBIND6";
- /* FALLTHROUGH */
- case DH6S_CONFIRM:
- if (state->reason == NULL)
- state->reason = "REBOOT6";
- if (state->renew != 0) {
- int all_expired = 1;
-
- TAILQ_FOREACH(ap, &state->addrs, next) {
- if (ap->flags & IPV6_AF_STALE)
- continue;
- if (ap->prefix_vltime <= state->renew)
- logwarnx(
- "%s: %s will expire before renewal",
- ifp->name, ap->saddr);
- else
- all_expired = 0;
- }
- if (all_expired) {
- /* All address's vltime happens at or before
- * the configured T1 in the IA.
- * This is a badly configured server and we
- * have to use our own notion of what
- * T1 and T2 should be as a result.
- *
- * Doing this violates RFC 3315 22.4:
- * In a message sent by a server to a client,
- * the client MUST use the values in the T1
- * and T2 fields for the T1 and T2 parameters,
- * unless those values in those fields are 0.
- */
- logwarnx("%s: ignoring T1 %"PRIu32
- " to due address expiry",
- ifp->name, state->renew);
- state->renew = state->rebind = 0;
- }
- }
- if (state->renew == 0 && state->lowpl != ND6_INFINITE_LIFETIME)
- state->renew = (uint32_t)(state->lowpl * 0.5);
- if (state->rebind == 0 && state->lowpl != ND6_INFINITE_LIFETIME)
- state->rebind = (uint32_t)(state->lowpl * 0.8);
- break;
- default:
- state->reason = "UNKNOWN6";
- break;
- }
-
- if (state->state != DH6S_CONFIRM) {
- 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;
- }
-
- if (ifp->ctx->options & DHCPCD_TEST)
- script_runreason(ifp, "TEST");
- else {
- if (state->state == DH6S_INFORM)
- state->state = DH6S_INFORMED;
- else
- state->state = DH6S_BOUND;
- if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
- eloop_timeout_add_sec(ifp->ctx->eloop,
- (time_t)state->renew,
- state->state == DH6S_INFORMED ?
- dhcp6_startinform : dhcp6_startrenew, ifp);
- if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
- eloop_timeout_add_sec(ifp->ctx->eloop,
- (time_t)state->rebind, dhcp6_startrebind, ifp);
- if (state->expire != ND6_INFINITE_LIFETIME)
- eloop_timeout_add_sec(ifp->ctx->eloop,
- (time_t)state->expire, dhcp6_startexpire, ifp);
-
- dhcp6_deprecateaddrs(&state->addrs);
- ipv6_addaddrs(&state->addrs);
-
- if (state->state == DH6S_INFORMED)
- lognewinfo("%s: refresh in %"PRIu32" seconds",
- ifp->name, state->renew);
- else if (state->renew || state->rebind)
- lognewinfo("%s: renew in %"PRIu32", "
- "rebind in %"PRIu32", "
- "expire in %"PRIu32" seconds",
- ifp->name,
- state->renew, state->rebind, state->expire);
- else if (state->expire == 0)
- lognewinfo("%s: will expire", ifp->name);
- if_initrt(ifp->ctx, AF_INET6);
- rt_build(ifp->ctx, AF_INET6);
- dhcp6_writelease(ifp);
-#ifndef SMALL
- dhcp6_delegate_prefix(ifp);
-#endif
- dhcp6_script_try_run(ifp, 0);
- }
-
- if (ifp->ctx->options & DHCPCD_TEST ||
- (ifp->options->options & DHCPCD_INFORM &&
- !(ifp->ctx->options & DHCPCD_MASTER)))
- {
- eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
- }
+ dhcp6_bind(ifp, op);
}
static int