From: Roy Marples Date: Mon, 29 Jul 2019 07:39:57 +0000 (+0100) Subject: DHCP6: Change state to REQEST when any IA has NOBINDING status X-Git-Tag: v7.2.4~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b3a62c88b91444c46ddb2150321d2e9d7d347022;p=thirdparty%2Fdhcpcd.git DHCP6: Change state to REQEST when any IA has NOBINDING status Just to be more RFC conformant. --- diff --git a/src/dhcp6.c b/src/dhcp6.c index dc911ee9..2e85f0e6 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -1931,6 +1931,7 @@ dhcp6_checkstatusok(const struct interface *ifp, if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) { //logdebugx("%s: no status", ifp->name); state->lerror = 0; + errno = ESRCH; return 0; } @@ -1942,7 +1943,8 @@ dhcp6_checkstatusok(const struct interface *ifp, code = ntohs(code); if (code == D6_STATUS_OK) { state->lerror = 0; - return 1; + errno = 0; + return 0; } /* Anything after the code is a message. */ @@ -1973,7 +1975,8 @@ dhcp6_checkstatusok(const struct interface *ifp, logfunc("%s: DHCPv6 REPLY: %s", ifp->name, status); free(sbuf); state->lerror = code; - return -1; + errno = 0; + return (int)code; } const struct ipv6_addr * @@ -2220,7 +2223,7 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l, struct dhcp6_option o; uint8_t *d, *p; struct dhcp6_ia_na ia; - int i, e; + int i, e, error; size_t j; uint16_t nl; uint8_t iaid[4]; @@ -2309,7 +2312,9 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l, } } else ia.t1 = ia.t2 = 0; /* appease gcc */ - if (dhcp6_checkstatusok(ifp, NULL, p, o.len) == -1) { + if ((error = dhcp6_checkstatusok(ifp, NULL, p, o.len)) != 0) { + if (error == D6_STATUS_NOBINDING) + state->has_no_binding = true; e = 1; continue; } @@ -2410,7 +2415,7 @@ dhcp6_validatelease(struct interface *ifp, const char *sfrom, const struct timespec *acquired) { struct dhcp6_state *state; - int ok, nia; + int nia, ok_errno; struct timespec aq; if (len <= sizeof(*m)) { @@ -2419,8 +2424,10 @@ dhcp6_validatelease(struct interface *ifp, } state = D6_STATE(ifp); - if ((ok = dhcp6_checkstatusok(ifp, m, NULL, len) == -1)) + errno = 0; + if (dhcp6_checkstatusok(ifp, m, NULL, len) != 0) return -1; + ok_errno = errno; state->renew = state->rebind = state->expire = 0; state->lowpl = ND6_INFINITE_LIFETIME; @@ -2428,9 +2435,10 @@ dhcp6_validatelease(struct interface *ifp, clock_gettime(CLOCK_MONOTONIC, &aq); acquired = &aq; } + state->has_no_binding = false; nia = dhcp6_findia(ifp, m, len, sfrom, acquired); if (nia == 0) { - if (state->state != DH6S_CONFIRM && ok != 1) { + if (state->state != DH6S_CONFIRM && ok_errno != 0) { logerrx("%s: no useable IA found in lease", ifp->name); return -1; } @@ -2440,6 +2448,7 @@ dhcp6_validatelease(struct interface *ifp, * IA's must have existed here otherwise we would * have rejected it earlier. */ assert(state->new != NULL && state->new_len != 0); + state->has_no_binding = false; nia = dhcp6_findia(ifp, state->new, state->new_len, sfrom, acquired); } @@ -3279,7 +3288,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, case DHCP6_REPLY: switch(state->state) { case DH6S_INFORM: - if (dhcp6_checkstatusok(ifp, r, NULL, len) == -1) + if (dhcp6_checkstatusok(ifp, r, NULL, len) != 0) return; break; case DH6S_CONFIRM: @@ -3327,6 +3336,14 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, dhcp6_startdiscover(ifp); return; } + /* RFC8415 18.2.10.1 */ + if ((state->state == DH6S_RENEW || + state->state == DH6S_REBIND) && + state->has_no_binding) + { + dhcp6_startrequest(ifp); + return; + } if (state->state == DH6S_DISCOVER) state->state = DH6S_REQUEST; break; diff --git a/src/dhcp6.h b/src/dhcp6.h index 8853d7f8..40182754 100644 --- a/src/dhcp6.h +++ b/src/dhcp6.h @@ -207,6 +207,7 @@ struct dhcp6_state { char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) +3]; const char *reason; uint16_t lerror; /* Last error received from DHCPv6 reply. */ + bool has_no_binding; struct authstate auth; };