mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-24 02:24:35 +08:00
Because not all OS's send RTM_NEWADDR for a refreshed RA we need
to manage a list of all IPv6 addresses on an interface so that we can know if we need to wait for DAD to complete or not.
This commit is contained in:
parent
af4140cdb4
commit
d5690e937b
18
dhcp6.c
18
dhcp6.c
@ -1860,7 +1860,7 @@ dhcp6_handledata(__unused void *arg)
|
||||
const struct dhcp6_option *o;
|
||||
const struct dhcp_opt *opt;
|
||||
const struct if_options *ifo;
|
||||
const struct ipv6_addr *ap;
|
||||
struct ipv6_addr *ap;
|
||||
uint8_t has_new;
|
||||
int error;
|
||||
|
||||
@ -2129,11 +2129,14 @@ recv:
|
||||
len = 1;
|
||||
/* If all addresses have completed DAD run the script */
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (ap->flags & IPV6_AF_ONLINK &&
|
||||
(ap->flags & IPV6_AF_DADCOMPLETED) == 0)
|
||||
{
|
||||
len = 0;
|
||||
break;
|
||||
if (ap->flags & IPV6_AF_ONLINK) {
|
||||
if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
|
||||
ipv6_findaddr(ap->iface, &ap->addr))
|
||||
ap->flags |= IPV6_AF_DADCOMPLETED;
|
||||
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len) {
|
||||
@ -2373,6 +2376,9 @@ dhcp6_handleifa(int cmd, const char *ifname,
|
||||
struct interface *ifp;
|
||||
struct dhcp6_state *state;
|
||||
|
||||
if (ifaces == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(ifp, ifaces, next) {
|
||||
state = D6_STATE(ifp);
|
||||
if (state == NULL || strcmp(ifp->name, ifname))
|
||||
|
@ -332,8 +332,8 @@ link_addr(struct nlmsghdr *nlm)
|
||||
errno = EBADMSG;
|
||||
return -1;
|
||||
}
|
||||
if (nlm->nlmsg_pid == (uint32_t)getpid())
|
||||
return 1;
|
||||
// if (nlm->nlmsg_pid == (uint32_t)getpid())
|
||||
// return 1;
|
||||
ifa = NLMSG_DATA(nlm);
|
||||
if (if_indextoname(ifa->ifa_index, ifn) == NULL)
|
||||
return -1;
|
||||
|
76
ipv6.c
76
ipv6.c
@ -141,8 +141,7 @@ int
|
||||
ipv6_makeaddr(struct in6_addr *addr, const struct interface *ifp,
|
||||
const struct in6_addr *prefix, int prefix_len)
|
||||
{
|
||||
const struct ipv6_state *state;
|
||||
const struct ll_addr *ap;
|
||||
const struct ipv6_addr_l *ap;
|
||||
#if 0
|
||||
static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
static u_int8_t allone[8] =
|
||||
@ -157,14 +156,11 @@ ipv6_makeaddr(struct in6_addr *addr, const struct interface *ifp,
|
||||
memcpy(addr, prefix, sizeof(*prefix));
|
||||
|
||||
/* Try and make the address from the first local-link address */
|
||||
state = IPV6_CSTATE(ifp);
|
||||
if (state) {
|
||||
ap = TAILQ_FIRST(&state->ll_addrs);
|
||||
if (ap) {
|
||||
addr->s6_addr32[2] = ap->addr.s6_addr32[2];
|
||||
addr->s6_addr32[3] = ap->addr.s6_addr32[3];
|
||||
return 0;
|
||||
}
|
||||
ap = ipv6_linklocal(ifp);
|
||||
if (ap) {
|
||||
addr->s6_addr32[2] = ap->addr.s6_addr32[2];
|
||||
addr->s6_addr32[3] = ap->addr.s6_addr32[3];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Because we delay a few functions until we get a local-link address
|
||||
@ -412,6 +408,9 @@ 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 (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
|
||||
ipv6_findaddr(ap->iface, &ap->addr))
|
||||
ap->flags |= IPV6_AF_DADCOMPLETED;
|
||||
if (add_address6(ap) == -1) {
|
||||
syslog(LOG_ERR, "add_address6 %m");
|
||||
return -1;
|
||||
@ -455,7 +454,7 @@ ipv6_getstate(struct interface *ifp)
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
return NULL;
|
||||
}
|
||||
TAILQ_INIT(&state->ll_addrs);
|
||||
TAILQ_INIT(&state->addrs);
|
||||
TAILQ_INIT(&state->ll_callbacks);
|
||||
}
|
||||
return state;
|
||||
@ -467,7 +466,7 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct ipv6_state *state;
|
||||
struct ll_addr *ap;
|
||||
struct ipv6_addr_l *ap;
|
||||
struct ll_callback *cb;
|
||||
|
||||
#if 0
|
||||
@ -503,21 +502,20 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
|
||||
return;
|
||||
}
|
||||
|
||||
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 (!IN6_IS_ADDR_LINKLOCAL(addr)) {
|
||||
ipv6rs_handleifa(cmd, ifname, addr, flags);
|
||||
dhcp6_handleifa(cmd, ifname, addr, flags);
|
||||
}
|
||||
|
||||
/* We don't care about duplicated addresses, so remove them */
|
||||
if (flags & IN6_IFF_DUPLICATED)
|
||||
cmd = RTM_DELADDR;
|
||||
|
||||
TAILQ_FOREACH(ap, &state->ll_addrs, next) {
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
|
||||
break;
|
||||
}
|
||||
@ -525,7 +523,7 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
|
||||
switch (cmd) {
|
||||
case RTM_DELADDR:
|
||||
if (ap) {
|
||||
TAILQ_REMOVE(&state->ll_addrs, ap, next);
|
||||
TAILQ_REMOVE(&state->addrs, ap, next);
|
||||
free(ap);
|
||||
}
|
||||
break;
|
||||
@ -534,7 +532,7 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
|
||||
ap = calloc(1, sizeof(*ap));
|
||||
memcpy(ap->addr.s6_addr, addr->s6_addr,
|
||||
sizeof(ap->addr.s6_addr));
|
||||
TAILQ_INSERT_TAIL(&state->ll_addrs,
|
||||
TAILQ_INSERT_TAIL(&state->addrs,
|
||||
ap, next);
|
||||
|
||||
/* Now run any callbacks.
|
||||
@ -551,14 +549,35 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
|
||||
}
|
||||
}
|
||||
|
||||
const struct ll_addr *
|
||||
const struct ipv6_addr_l *
|
||||
ipv6_linklocal(const struct interface *ifp)
|
||||
{
|
||||
const struct ipv6_state *state;
|
||||
const struct ipv6_addr_l *ap;
|
||||
|
||||
state = IPV6_CSTATE(ifp);
|
||||
if (state)
|
||||
return TAILQ_FIRST(&state->ll_addrs);
|
||||
if (state) {
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&ap->addr))
|
||||
return ap;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct ipv6_addr_l *
|
||||
ipv6_findaddr(const struct interface *ifp, const struct in6_addr *addr)
|
||||
{
|
||||
const struct ipv6_state *state;
|
||||
const struct ipv6_addr_l *ap;
|
||||
|
||||
state = IPV6_CSTATE(ifp);
|
||||
if (state) {
|
||||
TAILQ_FOREACH(ap, &state->addrs, next) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
|
||||
return ap;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -600,17 +619,18 @@ ipv6_free_ll_callbacks(struct interface *ifp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ipv6_free(struct interface *ifp)
|
||||
{
|
||||
struct ipv6_state *state;
|
||||
struct ll_addr *ap;
|
||||
struct ipv6_addr_l *ap;
|
||||
|
||||
ipv6_free_ll_callbacks(ifp);
|
||||
state = IPV6_STATE(ifp);
|
||||
if (state) {
|
||||
while ((ap = TAILQ_FIRST(&state->ll_addrs))) {
|
||||
TAILQ_REMOVE(&state->ll_addrs, ap, next);
|
||||
while ((ap = TAILQ_FIRST(&state->addrs))) {
|
||||
TAILQ_REMOVE(&state->addrs, ap, next);
|
||||
free(ap);
|
||||
}
|
||||
free(state);
|
||||
|
12
ipv6.h
12
ipv6.h
@ -113,12 +113,12 @@ struct rt6 {
|
||||
};
|
||||
TAILQ_HEAD(rt6head, rt6);
|
||||
|
||||
struct ll_addr {
|
||||
TAILQ_ENTRY(ll_addr) next;
|
||||
struct ipv6_addr_l {
|
||||
TAILQ_ENTRY(ipv6_addr_l) next;
|
||||
struct in6_addr addr;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(ll_addr_head, ll_addr);
|
||||
TAILQ_HEAD(ipv6_addr_l_head, ipv6_addr_l);
|
||||
|
||||
struct ll_callback {
|
||||
TAILQ_ENTRY(ll_callback) next;
|
||||
@ -128,7 +128,7 @@ struct ll_callback {
|
||||
TAILQ_HEAD(ll_callback_head, ll_callback);
|
||||
|
||||
struct ipv6_state {
|
||||
struct ll_addr_head ll_addrs;
|
||||
struct ipv6_addr_l_head addrs;
|
||||
struct ll_callback_head ll_callbacks;
|
||||
};
|
||||
|
||||
@ -151,7 +151,9 @@ void ipv6_handleifa(int, struct if_head *,
|
||||
const char *, const struct in6_addr *, int);
|
||||
int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
|
||||
const struct in6_addr *, int);
|
||||
const struct ll_addr *ipv6_linklocal(const struct interface *);
|
||||
const struct ipv6_addr_l *ipv6_linklocal(const struct interface *);
|
||||
const struct ipv6_addr_l *ipv6_findaddr(const struct interface *,
|
||||
const struct in6_addr *);
|
||||
int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
|
||||
void ipv6_free_ll_callbacks(struct interface *);
|
||||
void ipv6_free(struct interface *);
|
||||
|
21
ipv6rs.c
21
ipv6rs.c
@ -406,20 +406,25 @@ add_router(struct ra *router)
|
||||
}
|
||||
|
||||
static void
|
||||
ipv6rs_scriptrun(const struct ra *rap)
|
||||
ipv6rs_scriptrun(struct ra *rap)
|
||||
{
|
||||
int hasdns;
|
||||
const struct ipv6_addr *ap;
|
||||
struct ipv6_addr *ap;
|
||||
const struct ra_opt *rao;
|
||||
|
||||
/* If all addresses have completed DAD run the script */
|
||||
TAILQ_FOREACH(ap, &rap->addrs, next) {
|
||||
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: waiting for Router Advertisement"
|
||||
" DAD to complete",
|
||||
rap->iface->name);
|
||||
return;
|
||||
if (ap->flags & IPV6_AF_ONLINK) {
|
||||
if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
|
||||
ipv6_findaddr(ap->iface, &ap->addr))
|
||||
ap->flags |= IPV6_AF_DADCOMPLETED;
|
||||
if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
|
||||
syslog(LOG_DEBUG,
|
||||
"%s: waiting for Router Advertisement"
|
||||
" DAD to complete",
|
||||
rap->iface->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
15
net.c
15
net.c
@ -441,21 +441,18 @@ discover_interfaces(int argc, char * const *argv)
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
/* Capture local link addresses */
|
||||
for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr != NULL &&
|
||||
ifa->ifa_addr->sa_family == AF_INET6)
|
||||
{
|
||||
sin6 = (const struct sockaddr_in6 *)
|
||||
(void *)ifa->ifa_addr;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
|
||||
ifa_flags = in6_addr_flags(ifa->ifa_name,
|
||||
&sin6->sin6_addr);
|
||||
if (ifa_flags != -1)
|
||||
ipv6_handleifa(RTM_NEWADDR, ifs,
|
||||
ifa->ifa_name,
|
||||
&sin6->sin6_addr, ifa_flags);
|
||||
}
|
||||
ifa_flags = in6_addr_flags(ifa->ifa_name,
|
||||
&sin6->sin6_addr);
|
||||
if (ifa_flags != -1)
|
||||
ipv6_handleifa(RTM_NEWADDR, ifs,
|
||||
ifa->ifa_name,
|
||||
&sin6->sin6_addr, ifa_flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user