From: Roy Marples Date: Tue, 4 Jun 2013 13:39:02 +0000 (+0000) Subject: Keep state of delegated addresses X-Git-Tag: v6.0.0~58 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e619948557c854dbd3c405095db4cdccb6418788;p=thirdparty%2Fdhcpcd.git Keep state of delegated addresses Handle RTM_NEWADDR messages a little better Delete addresses with pltime of 0 --- diff --git a/dhcp6.c b/dhcp6.c index eec54992..d3706b95 100644 --- 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; } } diff --git a/if-bsd.c b/if-bsd.c index b82a71db..93bc95a8 100644 --- 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. diff --git a/if-linux.c b/if-linux.c index 9a02b60a..e0b6587a 100644 --- a/if-linux.c +++ b/if-linux.c @@ -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 78e296c3..5a219d30 100644 --- 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 40c1c11c..190f056f 100644 --- 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 *, diff --git a/ipv6ns.c b/ipv6ns.c index 11a9ce51..aba742a6 100644 --- 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; diff --git a/ipv6rs.c b/ipv6rs.c index a31cd361..5a4f293b 100644 --- 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 85f6289e..2772e56a 100644 --- 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);