dhcp6_dadcallback(void *arg)
{
struct ipv6_addr *ap = arg;
+ struct interface *ifp;
+ struct dhcp6_state *state;
+ int wascompleted;
+ wascompleted = ap->dadcompleted;
ipv6ns_cancelprobeaddr(ap);
ap->dadcompleted = 1;
if (ap->dad)
* We should decline the address */
syslog(LOG_WARNING, "%s: DAD detected %s",
ap->iface->name, ap->saddr);
-#ifdef IPV6_SEND_DAD
else
+#ifdef IPV6_SEND_DAD
ipv6_addaddr(ap);
#endif
+
+ if (!wascompleted) {
+ ifp = ap->iface;
+ state = D6_STATE(ifp);
+ if (state->state == DH6S_BOUND) {
+ TAILQ_FOREACH(ap, &state->addrs, next) {
+ if (!ap->dadcompleted) {
+ wascompleted = 1;
+ break;
+ }
+ }
+ if (!wascompleted) {
+ syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
+ ifp->name);
+ script_runreason(ifp, state->reason);
+ daemonise();
+ }
+ }
+ }
}
static int
script_runreason(ifp, state->reason);
daemonise();
} else
- syslog(LOG_DEBUG, "%s: waiting for RA DAD to complete",
+ syslog(LOG_DEBUG, "%s: waiting for DHCPv6 DAD"
+ " to complete",
ifp->name);
}
}
void
-dhcp6_handleifa(int cmd, const char *ifname, const struct in6_addr *addr)
+dhcp6_handleifa(int cmd, const char *ifname,
+ const struct in6_addr *addr, int flags)
{
struct interface *ifp;
struct dhcp6_state *state;
- int found;
TAILQ_FOREACH(ifp, ifaces, next) {
state = D6_STATE(ifp);
if (state == NULL || strcmp(ifp->name, ifname))
continue;
- found = ipv6_handleifa_addrs(cmd, &state->addrs, addr);
- if (found && state->state == DH6S_BOUND) {
- syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
- ifp->name);
- script_runreason(ifp, state->reason);
- daemonise();
- }
+ ipv6_handleifa_addrs(cmd, &state->addrs, addr, flags);
}
}
ssize_t dhcp6_env(char **, const char *, const struct interface *,
const struct dhcp6_message *, ssize_t);
void dhcp6_free(struct interface *);
-void dhcp6_handleifa(int, const char *, const struct in6_addr *addr);
+void dhcp6_handleifa(int, const char *, const struct in6_addr *addr, int);
void dhcp6_drop(struct interface *, const char *);
#else
#define dhcp6_printoptions()
sin6->sin6_addr.s6_addr,
sizeof(ia6.s6_addr));
ipv6_handleifa(rtm->rtm_type, ifname,
- &ia6);
+ &ia6, ifam->ifam_flags);
break;
#endif
}
#ifdef __linux__
# include <asm/types.h> /* for systems with broken headers */
# include <linux/rtnetlink.h>
+ /* Match Linux defines to BSD */
+# define IN6_IFF_TENTATIVE IFA_F_TENTATIVE | IFA_F_OPTIMISTIC
+# define IN6_IFF_DUPLICATED IFA_F_DADFAILED
+#else
+# include <netinet6/in6_var.h>
#endif
#include <errno.h>
}
void
-ipv6_handleifa(int cmd, const char *ifname, const struct in6_addr *addr)
+ipv6_handleifa(int cmd, const char *ifname,
+ const struct in6_addr *addr, int flags)
{
- ipv6rs_handleifa(cmd, ifname, addr);
- dhcp6_handleifa(cmd, ifname, addr);
+ ipv6rs_handleifa(cmd, ifname, addr, flags);
+ dhcp6_handleifa(cmd, ifname, addr, flags);
}
int
ipv6_handleifa_addrs(int cmd,
- struct ipv6_addrhead *addrs, const struct in6_addr *addr)
+ struct ipv6_addrhead *addrs, const struct in6_addr *addr, int flags)
{
struct ipv6_addr *ap, *apn;
uint8_t found, alldadcompleted;
free(ap);
break;
case RTM_NEWADDR:
+ /* Safety - ignore tentative announcements */
+ if (flags & IN6_IFF_TENTATIVE)
+ break;
if (!ap->dadcompleted) {
found++;
+ if (flags & IN6_IFF_DUPLICATED && ap->dad == 0)
+ ap->dad = 1;
+ if (ap->dadcallback)
+ ap->dadcallback(ap);
+ /* We need to set this here in-case the
+ * dadcallback function checks it */
ap->dadcompleted = 1;
}
}
int ipv6_init(void);
ssize_t ipv6_printaddr(char *, ssize_t, const uint8_t *, const char *);
struct in6_addr *ipv6_linklocal(const char *);
-int ipv6_makeaddr(struct in6_addr *, const char *, const struct in6_addr *, int);
+int ipv6_makeaddr(struct in6_addr *, const char *,
+ const struct in6_addr *, int);
int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int);
int ipv6_mask(struct in6_addr *, int);
int ipv6_prefixlen(const struct in6_addr *);
int ipv6_addaddr(struct ipv6_addr *);
ssize_t ipv6_addaddrs(struct ipv6_addrhead *);
-void ipv6_handleifa(int, const char *, const struct in6_addr *);
-int ipv6_handleifa_addrs(int, struct ipv6_addrhead *, const struct in6_addr *);
+void ipv6_handleifa(int, const char *, const struct in6_addr *, int);
+int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
+ const struct in6_addr *, int);
int ipv6_removesubnet(const struct interface *, struct ipv6_addr *);
void ipv6_buildroutes(void);
void ipv6_drop(struct interface *);
script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
}
+#ifdef LISTEN_DAD
void
ipv6ns_cancelprobeaddr(struct ipv6_addr *ap)
{
if (ap->dadcallback)
eloop_timeout_delete(ap->dadcallback, ap);
}
+#endif
void
ipv6ns_probeaddr(void *arg)
struct in6_pktinfo pi;
int hoplimit = HOPLIMIT;
#else
+#ifdef LISTEN_DAD
+ struct timeval tv, rtv;
struct timeval mtv;
int i;
#endif
- struct timeval tv, rtv;
+#endif
if (ap->dadcallback &&
(ap->new == 0 || ap->nsprobes >= ap->iface->options->dadtransmits))
ap);
}
#else /* IPV6_SEND_DAD */
+ ipv6_addaddr(ap);
+#ifdef LISTEN_DAD
/* Let the kernel handle DAD.
* We don't know the timings, so just wait for the max */
- ipv6_addaddr(ap);
if (ap->dadcallback) {
mtv.tv_sec = 0;
mtv.tv_usec = 0;
}
eloop_timeout_add_tv(&mtv, ap->dadcallback, ap);
}
+#endif
#endif /* IPV6_SEND_DAD */
}
int found;
#endif
struct timeval tv;
+
+#ifdef LISTEN_DAD
struct dhcp6_state *d6state;
struct ipv6_addr *ap;
+#endif
len = recvmsg(sock, &rcvhdr, 0);
if (len == -1) {
if (memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
sizeof(rap->from.s6_addr)) == 0)
break;
+#ifdef LISTEN_DAD
TAILQ_FOREACH(ap, &rap->addrs, next) {
if (memcmp(ap->addr.s6_addr,
nd_na->nd_na_target.s6_addr,
#endif
}
}
+#endif
}
if (rap == NULL) {
+#ifdef LISTEN_DAD
d6state = D6_STATE(ifp);
if (d6state) {
TAILQ_FOREACH(ap, &d6state->addrs, next) {
}
}
}
+#endif
#ifdef DEBUG_NS
if (found == 0)
void ipv6ns_probeaddr(void *);
ssize_t ipv6ns_probeaddrs(struct ipv6_addrhead *);
-void ipv6ns_cancelprobeaddr(struct ipv6_addr *);
void ipv6ns_proberouter(void *);
+
+#ifdef LISTEN_DAD
+void ipv6ns_cancelprobeaddr(struct ipv6_addr *);
+#else
+#define ipv6ns_cancelprobeaddr(a)
+#endif
#endif
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
- syslog(LOG_INFO, "%s: sending IPv6 Router Solicitation", ifp->name);
+ syslog(LOG_INFO, "%s: sending Router Solicitation", ifp->name);
if (sendmsg(sock, &sndhdr, 0) == -1) {
syslog(LOG_ERR, "%s: sendmsg: %m", ifp->name);
ipv6rs_drop(ifp);
TAILQ_INSERT_HEAD(&ipv6_routers, router, next);
}
-static void
-ipv6rs_dadcallback(void *arg)
-{
- struct ipv6_addr *ap = arg;
-
- ipv6ns_cancelprobeaddr(ap);
- ap->dadcompleted = 1;
- if (ap->dad)
- /* No idea what how to try and make another address :( */
- syslog(LOG_WARNING, "%s: DAD detected %s",
- ap->iface->name, ap->saddr);
-#ifdef IPV6_SEND_DAD
- else
- ipv6_addaddr(ap);
-#endif
-}
-
static void
ipv6rs_scriptrun(const struct ra *rap)
{
/* If all addresses have completed DAD run the script */
TAILQ_FOREACH(ap, &rap->addrs, next) {
- if (ap->dadcompleted == 0)
+ if (ap->dadcompleted == 0) {
+ syslog(LOG_DEBUG, "%s: waiting for Router Advertisement"
+ " DAD to complete",
+ rap->iface->name);
return;
+ }
}
/* If we don't require RDNSS then set hasdns = 1 so we fork */
#endif
}
+static void
+ipv6rs_dadcallback(void *arg)
+{
+ struct ipv6_addr *ap = arg, *rapap;
+ struct interface *ifp;
+ struct ra *rap;
+ int wascompleted, found;
+
+ wascompleted = ap->dadcompleted;
+ ipv6ns_cancelprobeaddr(ap);
+ ap->dadcompleted = 1;
+ if (ap->dad)
+ /* No idea what how to try and make another address :( */
+ syslog(LOG_WARNING, "%s: DAD detected %s",
+ ap->iface->name, ap->saddr);
+#ifdef IPV6_SEND_DAD
+ else
+ ipv6_addaddr(ap);
+#endif
+
+ if (!wascompleted) {
+ ifp = ap->iface;
+
+ TAILQ_FOREACH(rap, &ipv6_routers, next) {
+ if (rap->iface != ifp)
+ continue;
+ wascompleted = 1;
+ TAILQ_FOREACH(rapap, &rap->addrs, next) {
+ if (!rapap->dadcompleted) {
+ wascompleted = 0;
+ break;
+ }
+ if (rapap == ap)
+ found = 1;
+ }
+
+ if (wascompleted && found && rap->lifetime) {
+ syslog(LOG_DEBUG,
+ "%s: Router Advertisement DAD completed",
+ rap->iface->name);
+ ipv6rs_scriptrun(rap);
+ }
+ }
+ }
+}
+
/* ARGSUSED */
static void
ipv6rs_handledata(__unused void *arg)
}
void
-ipv6rs_handleifa(int cmd, const char *ifname, const struct in6_addr *addr)
+ipv6rs_handleifa(int cmd, const char *ifname,
+ const struct in6_addr *addr, int flags)
{
struct ra *rap;
- int found;
TAILQ_FOREACH(rap, &ipv6_routers, next) {
if (strcmp(rap->iface->name, ifname))
continue;
- found = ipv6_handleifa_addrs(cmd, &rap->addrs, addr);
- if (found && rap->lifetime) {
- syslog(LOG_DEBUG,
- "%s: IPv6 Router Advertisement DAD completed",
- rap->iface->name);
- ipv6rs_scriptrun(rap);
- }
+ ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
}
}
ssize_t ipv6rs_free(struct interface *);
void ipv6rs_expire(void *arg);
int ipv6rs_has_ra(const struct interface *);
-void ipv6rs_handleifa(int, const char *, const struct in6_addr *);
+void ipv6rs_handleifa(int, const char *, const struct in6_addr *, int);
void ipv6rs_drop(struct interface *);
#else
#define ipv6rs_start(a) {}