summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2019-07-29 08:39:57 +0100
committerRoy Marples <roy@marples.name>2019-07-29 08:42:16 +0100
commit9a1551057efc100c0621752da5c372b2d08f6193 (patch)
tree90d8bf5338181c9d408824f3018e6e8537bb8356
parent5ca93a3ab42ee2293db1f84662603ec0c2966f52 (diff)
downloaddhcpcd-9a1551057efc100c0621752da5c372b2d08f6193.tar.xz
DHCP6: Change state to REQEST when any IA has NOBINDING statusdhcpcd-7
Just to be more RFC conformant.
-rw-r--r--src/dhcp6.c33
-rw-r--r--src/dhcp6.h1
2 files changed, 26 insertions, 8 deletions
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;
};