]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
DHCP6: Change state to REQEST when any IA has NOBINDING status
authorRoy Marples <roy@marples.name>
Mon, 29 Jul 2019 07:39:57 +0000 (08:39 +0100)
committerRoy Marples <roy@marples.name>
Mon, 29 Jul 2019 07:42:16 +0000 (08:42 +0100)
Just to be more RFC conformant.

src/dhcp6.c
src/dhcp6.h

index dc911ee93b931b47985f6547941649d2c1662109..2e85f0e63cfb38fcd3402799df7c671a5e6eb9b1 100644 (file)
@@ -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;
index 8853d7f8a2d6dbc111967841024bc56d0e3d8821..40182754d7f589a051779adb3ce8e121f4b9fb3e 100644 (file)
@@ -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;
 };