]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Keep state of delegated addresses
authorRoy Marples <roy@marples.name>
Tue, 4 Jun 2013 13:39:02 +0000 (13:39 +0000)
committerRoy Marples <roy@marples.name>
Tue, 4 Jun 2013 13:39:02 +0000 (13:39 +0000)
Handle RTM_NEWADDR messages a little better
Delete addresses with pltime of 0

dhcp6.c
if-bsd.c
if-linux.c
ipv6.c
ipv6.h
ipv6ns.c
ipv6rs.c
net.h

diff --git a/dhcp6.c b/dhcp6.c
index eec549926a67bc1769f6b7e764e717cc03b26e11..d3706b95a20ce6b7064208eb83b80785469def2a 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -616,8 +616,8 @@ dhcp6_freedrop_addrs(struct interface *ifp, int drop)
                    !ipv6rs_addrexists(ap))
                {
                        syslog(LOG_INFO, "%s: deleting address %s",
-                           ifp->name, ap->saddr);
-                       if (del_address6(ifp, ap) == -1 &&
+                           ap->iface->name, ap->saddr);
+                       if (del_address6(ap) == -1 &&
                            errno != EADDRNOTAVAIL)
                                syslog(LOG_ERR, "del_address6 %m");
                }
@@ -1193,9 +1193,9 @@ dhcp6_findna(struct interface *ifp, const uint8_t *iaid,
                p += sizeof(u32);
                memcpy(&u32, p, sizeof(u32));
                a->prefix_vltime = ntohl(u32);
-               if (a->prefix_pltime < state->lowpl)
+               if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
                    state->lowpl = a->prefix_pltime;
-               if (a->prefix_vltime > state->expire)
+               if (a->prefix_vltime && a->prefix_vltime > state->expire)
                    state->expire = a->prefix_vltime;
                ia = inet_ntop(AF_INET6, &a->addr.s6_addr,
                    iabuf, sizeof(iabuf));
@@ -1254,9 +1254,9 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
                memcpy(&u32, p, sizeof(u32));
                p += sizeof(u32);
                a->prefix_vltime = ntohl(u32);
-               if (a->prefix_pltime < state->lowpl)
+               if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
                        state->lowpl = a->prefix_pltime;
-               if (a->prefix_vltime > state->expire)
+               if (a->prefix_vltime && a->prefix_vltime > state->expire)
                        state->expire = a->prefix_vltime;
                memcpy(&u8, p, sizeof(u8));
                p += sizeof(u8);
@@ -1600,8 +1600,9 @@ dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix,
        TAILQ_FOREACH(ap, &state->addrs, next) {
                if (IN6_ARE_ADDR_EQUAL(&ap->addr, &a->addr)) {
                        TAILQ_REMOVE(&state->addrs, ap, next);
+                       /* Keep our flags */
+                       a->flags |= ap->flags;
                        free(ap);
-                       break;
                }
        }
 
index b82a71db2868c476e3d5d93f6000e5f449848b10..93bc95a8621f0b3dc622b0403ba93b5f9295bc53 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -300,7 +300,7 @@ if_route(const struct rt *rt, int action)
 
 #ifdef INET6
 int
-if_address6(const struct interface *ifp, const struct ipv6_addr *a, int action)
+if_address6(const struct ipv6_addr *a, int action)
 {
        int s, r;
        struct in6_aliasreq ifa;
@@ -310,7 +310,7 @@ if_address6(const struct interface *ifp, const struct ipv6_addr *a, int action)
        if (s == -1)
                return -1;
        memset(&ifa, 0, sizeof(ifa));
-       strlcpy(ifa.ifra_name, ifp->name, sizeof(ifa.ifra_name));
+       strlcpy(ifa.ifra_name, a->iface->name, sizeof(ifa.ifra_name));
        /*
         * We should not set IN6_IFF_TENTATIVE as the kernel should be
         * able to work out if it's a new address or not.
index 9a02b60ae0a407b32a3f5fd9eb86908de661dd9e..e0b6587aa94c50a7421464b66da91759da9fd674 100644 (file)
@@ -644,7 +644,7 @@ if_route(const struct rt *rt, int action)
 
 #ifdef INET6
 int
-if_address6(const struct interface *ifp, const struct ipv6_addr *ap, int action)
+if_address6(const struct ipv6_addr *ap, int action)
 {
        struct nlma *nlm;
        struct ifa_cacheinfo cinfo;
@@ -660,7 +660,7 @@ if_address6(const struct interface *ifp, const struct ipv6_addr *ap, int action)
                nlm->hdr.nlmsg_type = RTM_NEWADDR;
        } else
                nlm->hdr.nlmsg_type = RTM_DELADDR;
-       nlm->ifa.ifa_index = ifp->index;
+       nlm->ifa.ifa_index = ap->iface->index;
        nlm->ifa.ifa_family = AF_INET6;
        nlm->ifa.ifa_prefixlen = ap->prefix_len;
        /* This creates the aliased interface */
diff --git a/ipv6.c b/ipv6.c
index 78e296c343d9931a2f24f9518c42296851979710..5a219d303534c8737abd0dc29ce4b624703a1cbc 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -412,7 +412,7 @@ ipv6_addaddr(struct ipv6_addr *ap)
 
        syslog(ap->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG,
            "%s: adding address %s", ap->iface->name, ap->saddr);
-       if (add_address6(ap->iface, ap) == -1) {
+       if (add_address6(ap) == -1) {
                syslog(LOG_ERR, "add_address6 %m");
                return -1;
        }
@@ -442,25 +442,6 @@ ipv6_addaddr(struct ipv6_addr *ap)
        return 0;
 }
 
-ssize_t
-ipv6_addaddrs(struct ipv6_addrhead *addrs)
-{
-       struct ipv6_addr *ap;
-       ssize_t i;
-
-       i = 0;
-       TAILQ_FOREACH(ap, addrs, next) {
-               if (ap->prefix_vltime == 0 ||
-                   IN6_IS_ADDR_UNSPECIFIED(&ap->addr) ||
-                   ap->flags & IPV6_AF_DELEGATED)
-                       continue;
-               if (ipv6_addaddr(ap) == 0)
-                       i++;
-       }
-
-       return i;
-}
-
 static struct ipv6_state *
 ipv6_getstate(struct interface *ifp)
 {
@@ -497,9 +478,9 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
            ifname, cmd, buf, flags);
 #endif
 
-       /* Safety - ignore tentative announcements */
+       /* Safety, remove tentative addresses */
        if (cmd == RTM_NEWADDR) {
-               if (flags & (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED))
+               if (flags & IN6_IFF_TENTATIVE)
                        cmd = RTM_DELADDR;
 #ifdef IN6_IFF_DETACHED
                if (flags & IN6_IFF_DETACHED)
@@ -522,47 +503,52 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
                return;
        }
 
-       if (IN6_IS_ADDR_LINKLOCAL(addr)) {
-               state = ipv6_getstate(ifp);
-               if (state == NULL)
-                       return;
-               TAILQ_FOREACH(ap, &state->ll_addrs, next) {
-                       if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
-                               break;
+       if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
+               ipv6rs_handleifa(cmd, ifname, addr, flags);
+               dhcp6_handleifa(cmd, ifname, addr, flags);
+               return;
+       }
+
+       state = ipv6_getstate(ifp);
+       if (state == NULL)
+               return;
+
+       /* We don't care about duplicated LL addresses, so remove them */
+       if (flags & IN6_IFF_DUPLICATED)
+               cmd = RTM_DELADDR;
+
+       TAILQ_FOREACH(ap, &state->ll_addrs, next) {
+               if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
+                       break;
+       }
+
+       switch (cmd) {
+       case RTM_DELADDR:
+               if (ap) {
+                       TAILQ_REMOVE(&state->ll_addrs, ap, next);
+                       free(ap);
                }
-               switch (cmd) {
-               case RTM_DELADDR:
-                       if (ap) {
-                               TAILQ_REMOVE(&state->ll_addrs, ap, next);
-                               free(ap);
-                       }
-                       return;
-               case RTM_NEWADDR:
-                       if (ap == NULL) {
-                               ap = calloc(1, sizeof(*ap));
-                               memcpy(ap->addr.s6_addr, addr->s6_addr,
-                                   sizeof(ap->addr.s6_addr));
-                               TAILQ_INSERT_TAIL(&state->ll_addrs,
-                                   ap, next);
-
-                               /* Now run any callbacks.
-                                * Typically IPv6RS or DHCPv6 */
-                               while ((cb = TAILQ_FIRST(&state->ll_callbacks)))
-                               {
-                                       TAILQ_REMOVE(&state->ll_callbacks,
-                                           cb, next);
-                                       cb->callback(cb->arg);
-                                       free(cb);
-                               }
+               break;
+       case RTM_NEWADDR:
+               if (ap == NULL) {
+                       ap = calloc(1, sizeof(*ap));
+                       memcpy(ap->addr.s6_addr, addr->s6_addr,
+                           sizeof(ap->addr.s6_addr));
+                       TAILQ_INSERT_TAIL(&state->ll_addrs,
+                           ap, next);
+
+                       /* Now run any callbacks.
+                        * Typically IPv6RS or DHCPv6 */
+                       while ((cb = TAILQ_FIRST(&state->ll_callbacks)))
+                       {
+                               TAILQ_REMOVE(&state->ll_callbacks,
+                                   cb, next);
+                               cb->callback(cb->arg);
+                               free(cb);
                        }
-                       return;
-               default:
-                       return;
                }
+               break;
        }
-
-       ipv6rs_handleifa(cmd, ifname, addr, flags);
-       dhcp6_handleifa(cmd, ifname, addr, flags);
 }
 
 const struct ll_addr *
@@ -662,6 +648,8 @@ ipv6_handleifa_addrs(int cmd,
                                found++;
                                if (flags & IN6_IFF_DUPLICATED)
                                        ap->flags |= IPV6_AF_DUPLICATED;
+                               else
+                                       ap->flags &= ~IPV6_AF_DUPLICATED;
                                if (ap->dadcallback)
                                        ap->dadcallback(ap);
                                /* We need to set this here in-case the
diff --git a/ipv6.h b/ipv6.h
index 40c1c11c08ca9dbaa1f89fc69fd5b8ccb7eac511..190f056f8199c5657511a6f7b2350ec29d8a27de 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
@@ -147,7 +147,6 @@ int ipv6_prefixlen(const struct in6_addr *);
 int ipv6_userprefix( const struct in6_addr *, short prefix_len,
     uint64_t user_number, struct in6_addr *result, short result_len);
 int ipv6_addaddr(struct ipv6_addr *);
-ssize_t ipv6_addaddrs(struct ipv6_addrhead *);
 void ipv6_handleifa(int, struct if_head *,
     const char *, const struct in6_addr *, int);
 int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
index 11a9ce516618e86ce3fb22559cb7f80f38c093f2..aba742a67aa02d234f95c6d5f15c62c52f26a76e 100644 (file)
--- a/ipv6ns.c
+++ b/ipv6ns.c
@@ -381,18 +381,30 @@ ipv6ns_probeaddr(void *arg)
 ssize_t
 ipv6ns_probeaddrs(struct ipv6_addrhead *addrs)
 {
-       struct ipv6_addr *ap;
+       struct ipv6_addr *ap, *apn;
        ssize_t i;
 
        i = 0;
-       TAILQ_FOREACH(ap, addrs, next) {
-               if (ap->prefix_vltime == 0 ||
-                   IN6_IS_ADDR_UNSPECIFIED(&ap->addr) ||
-                   ap->flags & IPV6_AF_DELEGATED)
-                       continue;
-               ipv6ns_probeaddr(ap);
-               if (ap->flags & IPV6_AF_NEW)
-                       i++;
+       TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
+               if (ap->prefix_vltime == 0) {
+                       TAILQ_REMOVE(addrs, ap, next);
+                       if (ap->flags & IPV6_AF_ADDED)
+                               syslog(LOG_INFO, "%s: deleting address %s",
+                                   ap->iface->name, ap->saddr);
+                       if (del_address6(ap) == -1 &&
+                           errno != EADDRNOTAVAIL)
+                               syslog(LOG_ERR, "del_address6 %m");
+                       if (ap->dadcallback)
+                               eloop_q_timeout_delete(0, NULL,
+                                   ap->dadcallback);
+                       free(ap);
+               } else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
+                   !(ap->flags & IPV6_AF_DELEGATED))
+               {
+                       ipv6ns_probeaddr(ap);
+                       if (ap->flags & IPV6_AF_NEW)
+                               i++;
+               }
        }
 
        return i;
index a31cd3615e1d061c076e8d3b4878e71f1af13010..5a4f293bff9e36d6c5cb6d1dc48f88286a06e7b2 100644 (file)
--- a/ipv6rs.c
+++ b/ipv6rs.c
@@ -324,7 +324,7 @@ ipv6rs_freedrop_addrs(struct ra *rap, int drop)
                {
                        syslog(LOG_INFO, "%s: deleting address %s",
                            rap->iface->name, ap->saddr);
-                       if (del_address6(rap->iface, ap) == -1 &&
+                       if (del_address6(ap) == -1 &&
                            errno != EADDRNOTAVAIL)
                                syslog(LOG_ERR, "del_address6 %m");
                }
@@ -768,13 +768,6 @@ ipv6rs_handledata(__unused void *arg)
                                }
                                ap->dadcallback = ipv6rs_dadcallback;
                                TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
-                       } else if (ap->prefix_vltime !=
-                           ntohl(pi->nd_opt_pi_valid_time) ||
-                           ap->prefix_pltime !=
-                           ntohl(pi->nd_opt_pi_preferred_time) ||
-                           ap->flags & IPV6_AF_DUPLICATED)
-                       {
-                               ap->flags |= IPV6_AF_NEW;
                        }
                        if (pi->nd_opt_pi_flags_reserved &
                            ND_OPT_PI_FLAG_ONLINK)
@@ -784,7 +777,6 @@ ipv6rs_handledata(__unused void *arg)
                        ap->prefix_pltime =
                            ntohl(pi->nd_opt_pi_preferred_time);
                        ap->nsprobes = 0;
-                       ap->flags &= ~IPV6_AF_DUPLICATED;
                        if (opt) {
                                l = strlen(opt);
                                tmp = realloc(opt,
diff --git a/net.h b/net.h
index 85f6289e6873787b9b7c1387a8fc15c34f88309c..2772e56a736b5fae37bbfe23aee300ed08c186b4 100644 (file)
--- a/net.h
+++ b/net.h
@@ -103,9 +103,9 @@ int up_interface(struct interface *);
 int if_conf(struct interface *);
 int if_init(struct interface *);
 
-int if_address6(const struct interface *, const struct ipv6_addr *, int);
-#define add_address6(ifp, a) if_address6(ifp, a, 1)
-#define del_address6(ifp, a) if_address6(ifp, a, -1)
+int if_address6(const struct ipv6_addr *, int);
+#define add_address6(a) if_address6(a, 1)
+#define del_address6(a) if_address6(a, -1)
 int in6_addr_flags(const char *, const struct in6_addr *);
 
 int if_route6(const struct rt6 *rt, int);