return if_findindex(ctx->ifaces, scope);
if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
return ia->iface;
+ if ((ia = ipv6_finddstaddr(ctx, &sin->sin6_addr)))
+ return ia->iface;
break;
}
#endif
case AF_INET6:
{
struct in6_addr addr6, mask6;
+ const struct in6_addr *dstaddr6;
const struct sockaddr_in6 *sin6;
sin6 = (const void *)rti_info[RTAX_IFA];
addr6 = sin6->sin6_addr;
sin6 = (const void *)rti_info[RTAX_NETMASK];
mask6 = sin6->sin6_addr;
+ sin6 = (const void *)rti_info[RTAX_BRD];
+ dstaddr6 = sin6 ? &sin6->sin6_addr : NULL;
/*
* If the address was deleted, lets check if it's
#endif
ipv6_handleifa(ctx, ifam->ifam_type, NULL,
- ifp->name, &addr6, ipv6_prefixlen(&mask6), flags, pid);
+ ifp->name, &addr6, ipv6_prefixlen(&mask6),
+ dstaddr6, flags, pid);
break;
}
#endif
int ret;
#endif
#ifdef INET6
- struct in6_addr *local6 = NULL, *address6 = NULL;
+ struct in6_addr *local6 = NULL, *addr6 = NULL, *dstaddr6 = NULL;
int flags;
#endif
for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
switch (rta->rta_type) {
case IFA_ADDRESS:
- address6 = (struct in6_addr *)RTA_DATA(rta);
+ addr6 = (struct in6_addr *)RTA_DATA(rta);
+ break;
+ case IFA_BROADCAST:
+ dstaddr6 = (struct in6_addr *)RTA_DATA(rta);
break;
case IFA_LOCAL:
local6 = (struct in6_addr *)RTA_DATA(rta);
}
}
if (local6 != NULL)
- address6 = local6;
- if (address6 == NULL)
+ addr6 = local6;
+ if (addr6 == NULL)
break; /* should be impossible */
/* Validate RTM_DELADDR really means address deleted
* and anything else really means address exists. */
- flags = if_addrflags6(ifp, address6, NULL);
+ flags = if_addrflags6(ifp, addr6, NULL);
if (nlm->nlmsg_type == RTM_DELADDR) {
if (flags != -1)
break;
}
ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
- address6, ifa->ifa_prefixlen, ifa->ifa_flags,
- (pid_t)nlm->nlmsg_pid);
+ addr6, ifa->ifa_prefixlen, dstaddr6,
+ ifa->ifa_flags, (pid_t)nlm->nlmsg_pid);
break;
#endif
}
}
if (mtu != NULL)
- ifp->mtu = *(unsigned int *)RTA_DATA(mtu);
+ ifp->mtu = (int)*(unsigned int *)RTA_DATA(mtu);
/* Re-read hardware address and friends */
if (!(ifi->ifi_flags & IFF_UP)) {
sin = (const void *)sa;
if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
return ia->iface;
+ if ((ia = ipv6_finddstaddr(ctx, &sin->sin6_addr)))
+ return ia->iface;
break;
}
#endif
case AF_INET6:
{
struct in6_addr addr6, mask6;
+ const struct in6_addr *dstaddr6;
const struct sockaddr_in6 *sin6;
sin6 = (const void *)rti_info[RTAX_IFA];
addr6 = sin6->sin6_addr;
sin6 = (const void *)rti_info[RTAX_NETMASK];
mask6 = sin6->sin6_addr;
+ sin6 = (const void *)rti_info[RTAX_BRD];
+ dstaddr6 = sin6 ? &sin6->sin6_addr : NULL;
if (ifam->ifam_type == RTM_DELADDR) {
struct ipv6_addr *ia;
ipv6_handleifa(ctx,
ifam->ifam_type == RTM_CHGADDR ?
RTM_NEWADDR : ifam->ifam_type,
- NULL, ifalias, &addr6, ipv6_prefixlen(&mask6), flags, 0);
+ NULL, ifalias, &addr6, ipv6_prefixlen(&mask6),
+ dstaddr6, flags, 0);
break;
}
#endif
const struct sockaddr_in *addr, *net, *brd;
#endif
#ifdef INET6
- struct sockaddr_in6 *sin6, *net6;
+ struct sockaddr_in6 *addr6, *net6, *dstaddr6;
#endif
int addrflags;
#endif
#ifdef INET6
case AF_INET6:
- sin6 = (void *)ifa->ifa_addr;
+ addr6 = (void *)ifa->ifa_addr;
+ dstaddr6 = (void *)ifa->ifa_dstaddr;
net6 = (void *)ifa->ifa_netmask;
#ifdef __KAME__
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr))
/* Remove the scope from the address */
- sin6->sin6_addr.s6_addr[2] =
- sin6->sin6_addr.s6_addr[3] = '\0';
+ addr6->sin6_addr.s6_addr[2] =
+ addr6->sin6_addr.s6_addr[3] = '\0';
#endif
#ifndef HAVE_IFADDRS_ADDRFLAGS
- addrflags = if_addrflags6(ifp, &sin6->sin6_addr,
+ addrflags = if_addrflags6(ifp, &addr6->sin6_addr,
ifa->ifa_name);
if (addrflags == -1) {
if (errno != EEXIST && errno != EADDRNOTAVAIL) {
char dbuf[INET6_ADDRSTRLEN];
const char *dbp;
- dbp = inet_ntop(AF_INET6, &sin6->sin6_addr,
+ dbp = inet_ntop(AF_INET6, &addr6->sin6_addr,
dbuf, sizeof(dbuf));
logerr("%s: if_addrflags6: %s%%%s",
__func__, dbp, ifp->name);
}
#endif
ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
- ifa->ifa_name, &sin6->sin6_addr,
- ipv6_prefixlen(&net6->sin6_addr), addrflags, 0);
+ ifa->ifa_name, &addr6->sin6_addr,
+ ipv6_prefixlen(&net6->sin6_addr),
+ dstaddr6 ? &dstaddr6->sin6_addr : NULL,
+ addrflags, 0);
break;
#endif
}
/* Simulate the kernel announcing the new address. */
ipv6_handleifa(ia->iface->ctx, RTM_NEWADDR,
ia->iface->ctx->ifaces, ia->iface->name,
- &ia->addr, ia->prefix_len, flags, 0);
+ &ia->addr, ia->prefix_len, ia->dstaddr, flags, 0);
} else {
/* Still tentative? Check again in a bit. */
eloop_timeout_add_msec(ia->iface->ctx->eloop,
void
ipv6_handleifa(struct dhcpcd_ctx *ctx,
int cmd, struct if_head *ifs, const char *ifname,
- const struct in6_addr *addr, uint8_t prefix_len, int addrflags, pid_t pid)
+ const struct in6_addr *addr, uint8_t prefix_len,
+ const struct in6_addr *dstaddr, int addrflags, pid_t pid)
{
struct interface *ifp;
struct ipv6_state *state;
#endif
#if 0
- char dbuf[INET6_ADDRSTRLEN];
- const char *dbp;
-
- dbp = inet_ntop(AF_INET6, &addr->s6_addr,
- dbuf, INET6_ADDRSTRLEN);
- loginfox("%s: cmd %d addr %s addrflags %d",
- ifname, cmd, dbp, addrflags);
+ char abuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
+ const char *abp, *dbp;
+
+ abp = inet_ntop(AF_INET6, &addr->s6_addr, abuf, sizeof(abuf));
+ dbp = dstaddr ?
+ inet_ntop(AF_INET6, &dstaddr->s6_addr, dbuf, sizeof(dbuf))
+ : "::";
+ loginfox("%s: cmd %d addr %s dstaddr %s addrflags %d",
+ ifname, cmd, abp, dbp, addrflags);
#endif
if (ifs == NULL)
ia->addr_flags = addrflags;
TAILQ_INSERT_TAIL(&state->addrs, ia, next);
}
+ ia->dstaddr = dstaddr ? *dstaddr : in6addr_any;
ia->flags &= ~IPV6_AF_STALE;
#ifdef IPV6_MANAGETEMPADDR
if (ia->addr_flags & IN6_IFF_TEMPORARY)
return NULL;
}
+
+static struct ipv6_addr *
+ipv6_iffinddstaddr(const struct interface *ifp, const struct in6_addr *addr)
+{
+ struct ipv6_state *state;
+ struct ipv6_addr *ap;
+
+ state = IPV6_STATE(ifp);
+ if (state) {
+ TAILQ_FOREACH(ap, &state->addrs, next) {
+ if (IN6_ARE_ADDR_EQUAL(&ap->dstaddr, addr))
+ return ap;
+ }
+ }
+ return NULL;
+}
+
+struct ipv6_addr *
+ipv6_finddstaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr)
+{
+ struct interface *ifp;
+ struct ipv6_addr *ap;
+
+ TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+ ap = ipv6_iffinddstaddr(ifp, addr);
+ if (ap != NULL)
+ return ap;
+ }
+ return NULL;
+}
+
int
ipv6_addlinklocalcallback(struct interface *ifp,
void (*callback)(void *), void *arg)
if (ia->flags & IPV6_AF_STALE)
ipv6_handleifa(ifp->ctx, RTM_DELADDR,
ifp->ctx->ifaces, ifp->name,
- &ia->addr, ia->prefix_len, 0, getpid());
+ &ia->addr, ia->prefix_len,
+ &ia->dstaddr, 0, getpid());
}
}
struct timespec created;
struct timespec acquired;
struct in6_addr addr;
+ struct in6_addr dstaddr;
int addr_flags;
unsigned int flags;
char saddr[INET6_ADDRSTRLEN];
void ipv6_freedrop_addrs(struct ipv6_addrhead *, int, unsigned int,
const struct interface *);
void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
- const char *, const struct in6_addr *, uint8_t, int, pid_t);
+ const char *, const struct in6_addr *, uint8_t,
+ const struct in6_addr *, int, pid_t);
int ipv6_handleifa_addrs(int, struct ipv6_addrhead *, const struct ipv6_addr *,
pid_t);
struct ipv6_addr *ipv6_iffindaddr(struct interface *,
const struct in6_addr *, unsigned int);
struct ipv6_addr *ipv6_findmaskaddr(struct dhcpcd_ctx *,
const struct in6_addr *);
+struct ipv6_addr *ipv6_finddstaddr(struct dhcpcd_ctx *,
+ const struct in6_addr *);
#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL, IN6_IFF_NOTUSEABLE)
int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
void ipv6_setscope(struct sockaddr_in6 *, unsigned int);