]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Reduce code size by merging IPv6 ND with RS.
authorRoy Marples <roy@marples.name>
Tue, 20 Aug 2013 10:29:43 +0000 (10:29 +0000)
committerRoy Marples <roy@marples.name>
Tue, 20 Aug 2013 10:29:43 +0000 (10:29 +0000)
configure
dhcp6.c
dhcpcd.c
dhcpcd.h
ipv6.c
ipv6nd.c [moved from ipv6rs.c with 65% similarity]
ipv6nd.h [moved from ipv6rs.h with 65% similarity]
ipv6ns.c [deleted file]
ipv6ns.h [deleted file]
net.c
script.c

index 00dbfdb294fd8fcaf44fc5d794f5c5275e6720b6..69a5ad8067485e8e2953ddcc9ccc3860f747d12e 100755 (executable)
--- a/configure
+++ b/configure
@@ -339,7 +339,7 @@ if [ -z "$INET" -o "$INET" = yes ]; then
 fi
 if [ -z "$INET6" -o "$INET6" = yes ]; then
        echo "CPPFLAGS+=        -DINET6" >>$CONFIG_MK
-       echo "SRCS+=            ipv6.c ipv6rs.c ipv6ns.c dhcp6.c" >>$CONFIG_MK
+       echo "SRCS+=            ipv6.c ipv6nd.c dhcp6.c" >>$CONFIG_MK
 fi
 
 # NetBSD: Even if we build for $PREFIX, the clueless user might move us to /
diff --git a/dhcp6.c b/dhcp6.c
index 3cf69f3909a75519fdb54ef533f77849e6c5459e..9f4a14ae94367834e91c76e09bdfada24ae30bab 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -53,8 +53,7 @@
 #include "dhcp6.h"
 #include "duid.h"
 #include "eloop.h"
-#include "ipv6ns.h"
-#include "ipv6rs.h"
+#include "ipv6nd.h"
 #include "platform.h"
 #include "script.h"
 
@@ -1248,7 +1247,7 @@ dhcp6_dadcallback(void *arg)
        int wascompleted;
 
        wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
-       ipv6ns_cancelprobeaddr(ap);
+       ipv6nd_cancelprobeaddr(ap);
        ap->flags |= IPV6_AF_DADCOMPLETED;
        if (ap->flags & IPV6_AF_DUPLICATED)
                /* XXX FIXME
@@ -1328,7 +1327,7 @@ dhcp6_findna(struct interface *ifp, const uint8_t *iaid,
                        memcpy(&a->addr.s6_addr, &in6.s6_addr,
                            sizeof(in6.s6_addr));
                }
-               pa = ipv6rs_findprefix(a);
+               pa = ipv6nd_findprefix(a);
                if (pa) {
                        memcpy(&a->prefix, &pa->prefix,
                            sizeof(a->prefix));
@@ -1844,7 +1843,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
                }
                if (k && !carrier_warned) {
                        ifd_state = D6_STATE(ifd);
-                       ipv6ns_probeaddrs(&ifd_state->addrs);
+                       ipv6nd_probeaddrs(&ifd_state->addrs);
                }
        }
 }
@@ -1907,7 +1906,7 @@ dhcp6_find_delegates(struct interface *ifp)
                syslog(LOG_INFO, "%s: adding delegated prefixes", ifp->name);
                state = D6_STATE(ifp);
                state->state = DH6S_DELEGATED;
-               ipv6ns_probeaddrs(&state->addrs);
+               ipv6nd_probeaddrs(&state->addrs);
                ipv6_buildroutes();
        }
        return k;
@@ -2193,7 +2192,7 @@ recv:
                            dhcp6_startexpire, ifp);
                if (ifp->options->ia_type == D6_OPTION_IA_PD)
                        dhcp6_delegate_prefix(ifp);
-               ipv6ns_probeaddrs(&state->addrs);
+               ipv6nd_probeaddrs(&state->addrs);
                if (state->renew || state->rebind)
                        syslog(has_new ? LOG_INFO : LOG_DEBUG,
                            "%s: renew in %"PRIu32" seconds,"
index d68dc4a8055aea998fc7258839b217aa55713675..3a8102ac545294d6dc423caf575203b03fdb3d20 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -61,8 +61,7 @@ const char copyright[] = "Copyright (c) 2006-2013 Roy Marples";
 #include "if-pref.h"
 #include "ipv4.h"
 #include "ipv6.h"
-#include "ipv6ns.h"
-#include "ipv6rs.h"
+#include "ipv6nd.h"
 #include "net.h"
 #include "platform.h"
 #include "script.h"
@@ -279,7 +278,7 @@ stop_interface(struct interface *ifp)
        // Remove the interface from our list
        TAILQ_REMOVE(ifaces, ifp, next);
        dhcp6_drop(ifp, NULL);
-       ipv6rs_drop(ifp);
+       ipv6nd_drop(ifp);
        dhcp_drop(ifp, "STOP");
        dhcp_close(ifp);
        eloop_timeout_delete(NULL, ifp);
@@ -406,7 +405,7 @@ handle_carrier(int carrier, int flags, const char *ifname)
                        ifp->carrier = LINK_DOWN;
                        dhcp_close(ifp);
                        dhcp6_drop(ifp, "EXPIRE6");
-                       ipv6rs_drop(ifp);
+                       ipv6nd_drop(ifp);
                        /* Don't blindly delete our knowledge of LL addresses.
                         * We need to listen to what the kernel does with
                         * them as some OS's will remove, mark tentative or
@@ -449,7 +448,7 @@ start_interface(void *arg)
        if (ifo->options & DHCPCD_IPV6) {
                if (ifo->options & DHCPCD_IPV6RS &&
                    !(ifo->options & DHCPCD_INFORM))
-                       ipv6rs_start(ifp);
+                       ipv6nd_startrs(ifp);
 
                if (!(ifo->options & DHCPCD_IPV6RS)) {
                        if (ifo->options & DHCPCD_IA_FORCED)
@@ -795,7 +794,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                                        len++;
                                        if (D6_STATE_RUNNING(ifp))
                                                len++;
-                                       if (ipv6rs_has_ra(ifp))
+                                       if (ipv6nd_has_ra(ifp))
                                                len++;
                                }
                                len = write(fd->fd, &len, sizeof(len));
@@ -813,7 +812,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                                                len++;
                                                if (D6_STATE_RUNNING(ifp))
                                                        len++;
-                                               if (ipv6rs_has_ra(ifp))
+                                               if (ipv6nd_has_ra(ifp))
                                                        len++;
                                        }
                                }
@@ -1185,7 +1184,7 @@ main(int argc, char **argv)
 
 #if 0
        if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) {
-               syslog(LOG_ERR, "ipv6rs: %m");
+               syslog(LOG_ERR, "disable_rtadvd: %m");
                options &= ~DHCPCD_IPV6RS;
        }
 #endif
index 0fad506a3dad41a1d3a92f25f92c3f22cd3257d1..a55cef7ce8172fc22003e695073410cdb9b35551 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -45,7 +45,7 @@
 
 #define IF_DATA_DHCP   0
 #define IF_DATA_IPV6   1
-#define IF_DATA_IPV6RS 2
+#define IF_DATA_IPV6ND 2
 #define IF_DATA_DHCP6  3
 #define IF_DATA_MAX    4
 
diff --git a/ipv6.c b/ipv6.c
index f98ccad45782114ce86dbadc9c523209a47d52a9..84e3e156039bf66490c61fd70040f8d1dbd868cf 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -59,7 +59,7 @@
 #include "dhcp6.h"
 #include "eloop.h"
 #include "ipv6.h"
-#include "ipv6rs.h"
+#include "ipv6nd.h"
 
 /* Hackery at it's finest. */
 #ifndef s6_addr32
@@ -457,7 +457,7 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
                 * This is safe because the RA is removed from the list
                 * before we are called. */
                if (drop && ap->flags & IPV6_AF_ADDED &&
-                   !ipv6rs_addrexists(ap) && !dhcp6_addrexists(ap))
+                   !ipv6nd_addrexists(ap) && !dhcp6_addrexists(ap))
                {
                        syslog(LOG_INFO, "%s: deleting address %s",
                            ap->iface->name, ap->saddr);
@@ -535,7 +535,7 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
                return;
 
        if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
-               ipv6rs_handleifa(cmd, ifname, addr, flags);
+               ipv6nd_handleifa(cmd, ifname, addr, flags);
                dhcp6_handleifa(cmd, ifname, addr, flags);
        }
 
similarity index 65%
rename from ipv6rs.c
rename to ipv6nd.c
index 9601370b54726ea796664f8d70208f0262791d44..dcab8b4d8450a01cb182e70e0a945b49fcaed128 100644 (file)
--- a/ipv6rs.c
+++ b/ipv6nd.c
@@ -51,8 +51,7 @@
 #include "dhcp6.h"
 #include "eloop.h"
 #include "ipv6.h"
-#include "ipv6ns.h"
-#include "ipv6rs.h"
+#include "ipv6nd.h"
 #include "script.h"
 
 /* Debugging Router Solicitations is a lot of spam, so disable it */
@@ -103,9 +102,35 @@ struct nd_opt_dnssl {              /* DNSSL option RFC 6106 */
 #define RTPREF_RESERVED        (-2)
 #define RTPREF_INVALID (-3)    /* internal */
 
-struct rahead ipv6_routers = TAILQ_HEAD_INITIALIZER(ipv6_routers);
+#define MIN_RANDOM_FACTOR      500                             /* millisecs */
+#define MAX_RANDOM_FACTOR      1500                            /* millisecs */
+#define MIN_RANDOM_FACTOR_U    MIN_RANDOM_FACTOR * 1000        /* usecs */
+#define MAX_RANDOM_FACTOR_U    MAX_RANDOM_FACTOR * 1000        /* usecs */
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define IPV6_ADDR_INT32_ONE     1
+#define IPV6_ADDR_INT16_MLL     0xff02
+#elif BYTE_ORDER == LITTLE_ENDIAN
+#define IPV6_ADDR_INT32_ONE     0x01000000
+#define IPV6_ADDR_INT16_MLL     0x02ff
+#endif
+
+/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
+//#define DEBUG_NS
+//
+
+/* Currently, no known kernel allows us to send from the unspecified address
+ * which is required for DAD to work. This isn't that much of a problem as
+ * the kernel will do DAD for us correctly, however we don't know the exact
+ * randomness the kernel applies to the timeouts. So we just follow the same
+ * logic and have a little faith.
+ * This define is purely for completeness */
+// #define IPV6_SEND_DAD
 
 static int sock = -1;
+#ifdef IPV6_SEND_DAD
+static int unspec_sock = -1;
+#endif
 static struct sockaddr_in6 allrouters, from;
 static struct msghdr sndhdr;
 static struct iovec sndiov[2];
@@ -115,10 +140,14 @@ static struct iovec rcviov[2];
 static unsigned char *rcvbuf;
 static unsigned char ansbuf[1500];
 static char ntopbuf[INET6_ADDRSTRLEN];
+static const char *sfrom;
+static struct icmp6_filter filt;
+
+struct rahead ipv6_routers = TAILQ_HEAD_INITIALIZER(ipv6_routers);
 
 #if DEBUG_MEMORY
 static void
-ipv6rs_cleanup(void)
+ipv6nd_cleanup(void)
 {
 
        free(sndbuf);
@@ -127,11 +156,16 @@ ipv6rs_cleanup(void)
 #endif
 
 static int
-ipv6rs_open(void)
+ipv6nd_open(void)
 {
        int on;
        int len;
-       struct icmp6_filter filt;
+#ifdef IPV6_SEND_DAD
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in6 sin;
+       } su;
+#endif
 
        sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
        if (sock == -1)
@@ -162,7 +196,7 @@ ipv6rs_open(void)
 
        set_cloexec(sock);
 #if DEBUG_MEMORY
-       atexit(ipv6rs_cleanup);
+       atexit(ipv6nd_cleanup);
 #endif
 
        len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
@@ -198,7 +232,63 @@ eexit:
 }
 
 static int
-ipv6rs_makeprobe(struct interface *ifp)
+ipv6nd_naopen(void)
+{
+       static int naopen = 0;
+       struct icmp6_filter unspec_filt;
+#ifdef IPV6_SEND_DAD
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in6 sin;
+       } su;
+#endif
+
+       if (naopen)
+               return sock;
+
+       ICMP6_FILTER_SETBLOCKALL(&unspec_filt);
+
+#ifdef IPV6_SEND_DAD
+       /* We send DAD requests from the unspecified address. */
+       unspec_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+       if (unspec_sock == -1)
+               return -1;
+       if (setsockopt(unspec_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
+           &unspec_filt, sizeof(unspec_filt)) == -1)
+               goto eexit;
+       memset(&su, 0, sizeof(su));
+       su.sin.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+       su.sin.sin6_len = sizeof(su.sin);
+#endif
+       if (bind(unspec_sock, &su.sa, sizeof(su.sin)) == -1)
+               goto eexit;
+#endif
+
+       ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
+       if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
+           &filt, sizeof(filt)) == -1)
+               goto eexit;
+
+#ifdef LISTEN_DAD
+       syslog(LOG_WARNING, "kernel does not report DAD results to userland");
+       syslog(LOG_WARNING,
+           "warning listening to duplicated addresses on the wire");
+#endif
+
+       naopen = sock;
+       return sock;
+
+eexit:
+#ifdef LISTEN_DAD
+       close(unspec_sock);
+       unspec_sock = -1;
+#endif
+       return -1;
+}
+
+static int
+ipv6nd_makersprobe(struct interface *ifp)
 {
        struct rs_state *state;
        struct nd_router_solicit *rs;
@@ -223,7 +313,7 @@ ipv6rs_makeprobe(struct interface *ifp)
 }
 
 static void
-ipv6rs_sendprobe(void *arg)
+ipv6nd_sendrsprobe(void *arg)
 {
        struct interface *ifp = arg;
        struct rs_state *state;
@@ -236,7 +326,7 @@ ipv6rs_sendprobe(void *arg)
                syslog(LOG_DEBUG,
                    "%s: delaying Router Soliciation for LL address",
                    ifp->name);
-               ipv6_addlinklocalcallback(ifp, ipv6rs_sendprobe, ifp);
+               ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
                return;
        }
 
@@ -267,20 +357,20 @@ ipv6rs_sendprobe(void *arg)
        syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name);
        if (sendmsg(sock, &sndhdr, 0) == -1) {
                syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
-               ipv6rs_drop(ifp);
+               ipv6nd_drop(ifp);
                ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
                return;
        }
 
        if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
                eloop_timeout_add_sec(RTR_SOLICITATION_INTERVAL,
-                   ipv6rs_sendprobe, ifp);
+                   ipv6nd_sendrsprobe, ifp);
        else
                syslog(LOG_WARNING, "%s: no IPv6 Routers available", ifp->name);
 }
 
 static void
-ipv6rs_free_opts(struct ra *rap)
+ipv6nd_free_opts(struct ra *rap)
 {
        struct ra_opt *rao;
 
@@ -292,7 +382,7 @@ ipv6rs_free_opts(struct ra *rap)
 }
 
 int
-ipv6rs_addrexists(const struct ipv6_addr *a)
+ipv6nd_addrexists(const struct ipv6_addr *a)
 {
        struct ra *rap;
        struct ipv6_addr *ap;
@@ -306,7 +396,7 @@ ipv6rs_addrexists(const struct ipv6_addr *a)
        return 0;
 }
 
-void ipv6rs_freedrop_ra(struct ra *rap, int drop)
+void ipv6nd_freedrop_ra(struct ra *rap, int drop)
 {
 
        eloop_timeout_delete(NULL, rap->iface);
@@ -314,14 +404,14 @@ void ipv6rs_freedrop_ra(struct ra *rap, int drop)
        if (!drop)
                TAILQ_REMOVE(&ipv6_routers, rap, next);
        ipv6_freedrop_addrs(&rap->addrs, drop, NULL);
-       ipv6rs_free_opts(rap);
+       ipv6nd_free_opts(rap);
        free(rap->data);
        free(rap->ns);
        free(rap);
 }
 
 ssize_t
-ipv6rs_free(struct interface *ifp)
+ipv6nd_free(struct interface *ifp)
 {
        struct rs_state *state;
        struct ra *rap, *ran;
@@ -331,12 +421,12 @@ ipv6rs_free(struct interface *ifp)
        if (state) {
                free(state->rs);
                free(state);
-               ifp->if_data[IF_DATA_IPV6RS] = NULL;
+               ifp->if_data[IF_DATA_IPV6ND] = NULL;
        }
        n = 0;
        TAILQ_FOREACH_SAFE(rap, &ipv6_routers, next, ran) {
                if (rap->iface == ifp) {
-                       ipv6rs_free_ra(rap);
+                       ipv6nd_free_ra(rap);
                        n++;
                }
        }
@@ -380,7 +470,7 @@ add_router(struct ra *router)
 }
 
 static void
-ipv6rs_scriptrun(struct ra *rap)
+ipv6nd_scriptrun(struct ra *rap)
 {
        int hasdns;
        struct ipv6_addr *ap;
@@ -435,7 +525,7 @@ ipv6rs_scriptrun(struct ra *rap)
 }
 
 static void
-ipv6rs_dadcallback(void *arg)
+ipv6nd_dadcallback(void *arg)
 {
        struct ipv6_addr *ap = arg, *rapap;
        struct interface *ifp;
@@ -443,7 +533,7 @@ ipv6rs_dadcallback(void *arg)
        int wascompleted, found;
 
        wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
-       ipv6ns_cancelprobeaddr(ap);
+       ipv6nd_cancelprobeaddr(ap);
        ap->flags |= IPV6_AF_DADCOMPLETED;
        if (ap->flags & IPV6_AF_DUPLICATED)
                /* No idea what how to try and make another address :( */
@@ -476,23 +566,16 @@ ipv6rs_dadcallback(void *arg)
                                syslog(LOG_DEBUG,
                                    "%s: Router Advertisement DAD completed",
                                    rap->iface->name);
-                               ipv6rs_scriptrun(rap);
+                               ipv6nd_scriptrun(rap);
                        }
                }
        }
 }
 
-/* ARGSUSED */
 static void
-ipv6rs_handledata(__unused void *arg)
+ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
 {
-       ssize_t len, l, m, n, olen;
-       struct cmsghdr *cm;
-       int hoplimit;
-       struct in6_pktinfo pkt;
-       struct icmp6_hdr *icp;
-       struct interface *ifp;
-       const char *sfrom;
+       ssize_t l, m, n, olen;
        struct nd_router_advert *nd_ra;
        struct nd_opt_prefix_info *pi;
        struct nd_opt_mtu *mtu;
@@ -511,61 +594,16 @@ ipv6rs_handledata(__unused void *arg)
        struct timeval expire;
        uint8_t new_rap, new_data;
 
-       len = recvmsg(sock, &rcvhdr, 0);
-       if (len == -1) {
-               syslog(LOG_ERR, "recvmsg: %m");
-               return;
-       }
-       sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
-           ntopbuf, INET6_ADDRSTRLEN);
        if ((size_t)len < sizeof(struct nd_router_advert)) {
                syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom);
                return;
        }
 
-       pkt.ipi6_ifindex = hoplimit = 0;
-       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
-            cm;
-            cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
-       {
-               if (cm->cmsg_level != IPPROTO_IPV6)
-                       continue;
-               switch(cm->cmsg_type) {
-               case IPV6_PKTINFO:
-                       if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
-                               memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
-                       break;
-               case IPV6_HOPLIMIT:
-                       if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
-                               memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
-                       break;
-               }
-       }
-
-       if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
-               syslog(LOG_ERR,
-                   "IPv6 RA did not contain index or hop limit from %s",
-                   sfrom);
-               return;
-       }
-
-       icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
-       if (icp->icmp6_type != ND_ROUTER_ADVERT ||
-           icp->icmp6_code != 0)
-       {
-               syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom);
-               return;
-       }
-
        if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
                syslog(LOG_ERR, "RA from non local address %s", sfrom);
                return;
        }
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
-               if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
-                       break;
-       }
        if (ifp == NULL) {
 #ifdef DEBUG_RS
                syslog(LOG_DEBUG, "RA for unexpected interface from %s", sfrom);
@@ -759,7 +797,7 @@ ipv6rs_handledata(__unused void *arg)
                                        memset(&ap->addr, 0, sizeof(ap->addr));
                                        ap->saddr[0] = '\0';
                                }
-                               ap->dadcallback = ipv6rs_dadcallback;
+                               ap->dadcallback = ipv6nd_dadcallback;
                                TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
                        }
                        if (pi->nd_opt_pi_flags_reserved &
@@ -913,12 +951,12 @@ ipv6rs_handledata(__unused void *arg)
                goto handle_flag;
        }
        if (ifp->options->options & DHCPCD_IPV6RA_OWN)
-               ipv6ns_probeaddrs(&rap->addrs);
+               ipv6nd_probeaddrs(&rap->addrs);
        ipv6_buildroutes();
 
        /* We will get run by the expire function */
        if (rap->lifetime)
-               ipv6rs_scriptrun(rap);
+               ipv6nd_scriptrun(rap);
 
        eloop_timeout_delete(NULL, ifp);
        eloop_timeout_delete(NULL, rap); /* reachable timer */
@@ -930,7 +968,7 @@ ipv6rs_handledata(__unused void *arg)
        {
                rap->nsprobes = 0;
                if (rap->lifetime)
-                       ipv6ns_proberouter(rap);
+                       ipv6nd_proberouter(rap);
        }
 
 handle_flag:
@@ -951,11 +989,11 @@ handle_flag:
        }
 
        /* Expire should be called last as the rap object could be destroyed */
-       ipv6rs_expire(ifp);
+       ipv6nd_expirera(ifp);
 }
 
 int
-ipv6rs_has_ra(const struct interface *ifp)
+ipv6nd_has_ra(const struct interface *ifp)
 {
        const struct ra *rap;
 
@@ -966,7 +1004,7 @@ ipv6rs_has_ra(const struct interface *ifp)
 }
 
 ssize_t
-ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
+ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
 {
        ssize_t l;
        size_t len;
@@ -1079,7 +1117,7 @@ ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
 }
 
 const struct ipv6_addr *
-ipv6rs_findprefix(const struct ipv6_addr *a)
+ipv6nd_findprefix(const struct ipv6_addr *a)
 {
        const struct ra *rap;
        const struct ipv6_addr *ap;
@@ -1107,7 +1145,7 @@ ipv6rs_findprefix(const struct ipv6_addr *a)
 }
 
 void
-ipv6rs_handleifa(int cmd, const char *ifname,
+ipv6nd_handleifa(int cmd, const char *ifname,
     const struct in6_addr *addr, int flags)
 {
        struct ra *rap;
@@ -1120,7 +1158,7 @@ ipv6rs_handleifa(int cmd, const char *ifname,
 }
 
 void
-ipv6rs_expire(void *arg)
+ipv6nd_expirera(void *arg)
 {
        struct interface *ifp;
        struct ra *rap, *ran;
@@ -1146,7 +1184,7 @@ ipv6rs_expire(void *arg)
                                    "%s: %s: router expired",
                                    ifp->name, rap->sfrom);
                                rap->expired = expired = 1;
-                               ipv6ns_cancelproberouter(rap);
+                               ipv6nd_cancelproberouter(rap);
                        }
                } else {
                        valid = 1;
@@ -1197,36 +1235,560 @@ ipv6rs_expire(void *arg)
                /* No valid lifetimes are left on the RA, so we might
                 * as well punt it. */
                if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
-                       ipv6rs_free_ra(rap);
+                       ipv6nd_free_ra(rap);
        }
 
        if (timerisset(&next))
-               eloop_timeout_add_tv(&next, ipv6rs_expire, ifp);
+               eloop_timeout_add_tv(&next, ipv6nd_expirera, ifp);
+       if (expired) {
+               ipv6_buildroutes();
+               script_runreason(ifp, "ROUTERADVERT");
+       }
+}
+
+void
+ipv6nd_drop(struct interface *ifp)
+{
+       struct ra *rap;
+       int expired = 0;
+       TAILQ_HEAD(rahead, ra) rtrs;
+
+       eloop_timeout_delete(NULL, ifp);
+       TAILQ_INIT(&rtrs);
+       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+               if (rap->iface == ifp) {
+                       rap->expired = expired = 1;
+                       TAILQ_REMOVE(&ipv6_routers, rap, next);
+                       TAILQ_INSERT_TAIL(&rtrs, rap, next);
+               }
+       }
        if (expired) {
+               while ((rap = TAILQ_FIRST(&rtrs))) {
+                       TAILQ_REMOVE(&rtrs, rap, next);
+                       ipv6nd_drop_ra(rap);
+               }
+               ipv6_buildroutes();
+               script_runreason(ifp, "ROUTERADVERT");
+       }
+}
+static void
+ipv6nd_unreachable(void *arg)
+{
+       struct ra *rap = arg;
+       struct timeval tv;
+
+       /* We could add an unreachable flag and persist the information,
+        * but that is more effort than it's probably worth. */
+       syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
+           rap->iface->name, rap->sfrom);
+       rap->expired = 1;
+       ipv6_buildroutes();
+       script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
+
+       /* We should still test if it's reachable or not so
+        * incase it comes back to life and it's preferable. */
+       if (rap->reachable) {
+               ms_to_tv(&tv, rap->reachable);
+       } else {
+               tv.tv_sec = REACHABLE_TIME;
+               tv.tv_usec = 0;
+       }
+       eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap);
+}
+
+#ifdef LISTEN_DAD
+void
+ipv6nd_cancelprobeaddr(struct ipv6_addr *ap)
+{
+
+       eloop_timeout_delete(ipv6nd_probeaddr, ap);
+       if (ap->dadcallback)
+               eloop_timeout_delete(ap->dadcallback, ap);
+}
+#endif
+
+void
+ipv6nd_probeaddr(void *arg)
+{
+       struct ipv6_addr *ap = arg;
+#ifdef IPV6_SEND_DAD
+       struct nd_neighbor_solicit *ns;
+       struct nd_opt_hdr *nd;
+       struct sockaddr_in6 dst;
+       struct cmsghdr *cm;
+       struct in6_pktinfo pi;
+       int hoplimit = HOPLIMIT;
+#else
+#ifdef LISTEN_DAD
+       struct timeval tv, rtv;
+       struct timeval mtv;
+       int i;
+#endif
+#endif
+
+       if (ap->dadcallback &&
+           ((ap->flags & IPV6_AF_NEW) == 0 ||
+           ap->nsprobes >= ap->iface->options->dadtransmits))
+       {
+#ifdef IPV6_SEND_DAD
+               ap->dadcallback(ap);
+#else
+               ipv6_addaddr(ap);
+#endif
+               return;
+       }
+
+       if (ipv6nd_naopen() == -1)
+               return;
+
+       ap->flags &= ~IPV6_AF_DADCOMPLETED;
+
+#ifdef IPV6_SEND_DAD
+       if (!ap->ns) {
+               ap->nslen = sizeof(*ns) + ROUNDUP8(ap->iface->hwlen + 2);
+               ap->ns = calloc(1, ap->nslen);
+               if (ap->ns == NULL) {
+                       syslog(LOG_ERR, "%s: %m", __func__);
+                       return;
+               }
+               ns = (struct nd_neighbor_solicit *)(void *)ap->ns;
+               ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
+               //ns->nd_ns_cksum = 0;
+               //ns->nd_ns_code = 0;
+               //ns->nd_ns_reserved = 0;
+               ns->nd_ns_target = ap->addr;
+               nd = (struct nd_opt_hdr *)(ap->ns + sizeof(*ns));
+               nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+               nd->nd_opt_len = (ROUNDUP8(ap->iface->hwlen + 2)) >> 3;
+               memcpy(nd + 1, ap->iface->hwaddr, ap->iface->hwlen);
+       }
+
+       memset(&dst, 0, sizeof(dst));
+       dst.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+       dst.sin6_len = sizeof(dst);
+#endif
+       dst.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
+       dst.sin6_addr.s6_addr16[1] = 0;
+       dst.sin6_addr.s6_addr32[1] = 0;
+       dst.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
+       dst.sin6_addr.s6_addr32[3] = ap->addr.s6_addr32[3];
+       dst.sin6_addr.s6_addr[12] = 0xff;
+
+       //memcpy(&dst.sin6_addr, &ap->addr, sizeof(dst.sin6_addr));
+       dst.sin6_scope_id = ap->iface->index;
+
+       sndhdr.msg_name = (caddr_t)&dst;
+       sndhdr.msg_iov[0].iov_base = ap->ns;
+       sndhdr.msg_iov[0].iov_len = ap->nslen;
+
+       /* Set the outbound interface */
+       cm = CMSG_FIRSTHDR(&sndhdr);
+       cm->cmsg_level = IPPROTO_IPV6;
+       cm->cmsg_type = IPV6_PKTINFO;
+       cm->cmsg_len = CMSG_LEN(sizeof(pi));
+       memset(&pi, 0, sizeof(pi));
+       pi.ipi6_ifindex = ap->iface->index;
+       memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
+
+       /* Hop limit */
+       cm = CMSG_NXTHDR(&sndhdr, cm);
+       cm->cmsg_level = IPPROTO_IPV6;
+       cm->cmsg_type = IPV6_HOPLIMIT;
+       cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
+       memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
+
+#ifdef DEBUG_NS
+       syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
+           ap->iface->name, ap->saddr);
+       if (ap->dadcallback == NULL)
+               syslog(LOG_WARNING, "%s: no callback!", ap->iface->name);
+#endif
+       if (sendmsg(unspec_sock, &sndhdr, 0) == -1) {
+               syslog(LOG_ERR, "%s: %s: sendmsg: %m",
+                   ap->iface->name, __func__);
+               return;
+       }
+
+       if (ap->dadcallback) {
+               ms_to_tv(&tv, RETRANS_TIMER);
+               ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
+               timeradd(&tv, &rtv, &tv);
+               rtv.tv_sec = 0;
+               rtv.tv_usec = arc4random() %
+                   (MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
+               timeradd(&tv, &rtv, &tv);
+
+               eloop_timeout_add_tv(&tv,
+                   ++(ap->nsprobes) < ap->iface->options->dadtransmits ?
+                   ipv6nd_probeaddr : ap->dadcallback,
+                   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 */
+       if (ap->dadcallback) {
+               mtv.tv_sec = 0;
+               mtv.tv_usec = 0;
+               for (i = 0; i < ap->iface->options->dadtransmits; i++) {
+                       ms_to_tv(&tv, RETRANS_TIMER);
+                       ms_to_tv(&rtv, MAX_RANDOM_FACTOR);
+                       timeradd(&tv, &rtv, &tv);
+                       timeradd(&mtv, &tv, &mtv);
+               }
+               eloop_timeout_add_tv(&mtv, ap->dadcallback, ap);
+       }
+#endif
+#endif /* IPV6_SEND_DAD */
+}
+
+ssize_t
+ipv6nd_probeaddrs(struct ipv6_addrhead *addrs)
+{
+       struct ipv6_addr *ap, *apn;
+       ssize_t i;
+
+       i = 0;
+       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);
+                               i++;
+                       }
+                       if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
+                           del_address6(ap) == -1 &&
+                           errno != EADDRNOTAVAIL && errno != ENXIO)
+                               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))
+               {
+                       ipv6nd_probeaddr(ap);
+                       if (ap->flags & IPV6_AF_NEW)
+                               i++;
+               }
+       }
+
+       return i;
+}
+
+void
+ipv6nd_proberouter(void *arg)
+{
+       struct ra *rap = arg;
+       struct nd_neighbor_solicit *ns;
+       struct nd_opt_hdr *nd;
+       struct sockaddr_in6 dst;
+       struct cmsghdr *cm;
+       struct in6_pktinfo pi;
+       int hoplimit = HOPLIMIT;
+       struct timeval tv, rtv;
+
+       if (ipv6nd_naopen() == -1)
+               return;
+
+       if (!rap->ns) {
+               rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
+               rap->ns = calloc(1, rap->nslen);
+               if (rap->ns == NULL) {
+                       syslog(LOG_ERR, "%s: %m", __func__);
+                       return;
+               }
+               ns = (struct nd_neighbor_solicit *)(void *)rap->ns;
+               ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
+               //ns->nd_ns_cksum = 0;
+               //ns->nd_ns_code = 0;
+               //ns->nd_ns_reserved = 0;
+               ns->nd_ns_target = rap->from;
+               nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns));
+               nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+               nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3;
+               memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen);
+       }
+
+       memset(&dst, 0, sizeof(dst));
+       dst.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+       dst.sin6_len = sizeof(dst);
+#endif
+       memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr));
+       dst.sin6_scope_id = rap->iface->index;
+
+       sndhdr.msg_name = (caddr_t)&dst;
+       sndhdr.msg_iov[0].iov_base = rap->ns;
+       sndhdr.msg_iov[0].iov_len = rap->nslen;
+
+       /* Set the outbound interface */
+       cm = CMSG_FIRSTHDR(&sndhdr);
+       cm->cmsg_level = IPPROTO_IPV6;
+       cm->cmsg_type = IPV6_PKTINFO;
+       cm->cmsg_len = CMSG_LEN(sizeof(pi));
+       memset(&pi, 0, sizeof(pi));
+       pi.ipi6_ifindex = rap->iface->index;
+       memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
+
+       /* Hop limit */
+       cm = CMSG_NXTHDR(&sndhdr, cm);
+       cm->cmsg_level = IPPROTO_IPV6;
+       cm->cmsg_type = IPV6_HOPLIMIT;
+       cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
+       memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
+
+#ifdef DEBUG_NS
+       syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
+           rap->iface->name, rap->sfrom);
+#endif
+       if (sendmsg(sock, &sndhdr, 0) == -1) {
+               syslog(LOG_ERR, "%s: %s: sendmsg: %m",
+                   rap->iface->name, __func__);
+               return;
+       }
+
+       ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans);
+       ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
+       timeradd(&tv, &rtv, &tv);
+       rtv.tv_sec = 0;
+       rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U);
+       timeradd(&tv, &rtv, &tv);
+       eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap);
+
+       if (rap->nsprobes++ == 0)
+               eloop_timeout_add_sec(DELAY_FIRST_PROBE_TIME,
+                   ipv6nd_unreachable, rap);
+}
+
+void
+ipv6nd_cancelproberouter(struct ra *rap)
+{
+
+       eloop_timeout_delete(ipv6nd_proberouter, rap);
+       eloop_timeout_delete(ipv6nd_unreachable, rap);
+}
+
+/* ARGSUSED */
+static void
+ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
+{
+       struct nd_neighbor_advert *nd_na;
+       struct ra *rap;
+       int is_router, is_solicited;
+#ifdef DEBUG_NS
+       int found;
+#endif
+       struct timeval tv;
+
+#ifdef LISTEN_DAD
+       struct dhcp6_state *d6state;
+       struct ipv6_addr *ap;
+#endif
+
+       if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
+               syslog(LOG_ERR, "IPv6 NA packet too short from %s", sfrom);
+               return;
+       }
+
+       if (ifp == NULL) {
+#ifdef DEBUG_NS
+               syslog(LOG_DEBUG, "NA for unexpected interface from %s", sfrom);
+#endif
+               return;
+       }
+
+       nd_na = (struct nd_neighbor_advert *)icp;
+       is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
+       is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
+
+       if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
+               syslog(LOG_ERR, "%s: NA for multicast address from %s",
+                   ifp->name, sfrom);
+               return;
+       }
+
+#ifdef DEBUG_NS
+       found = 0;
+#endif
+       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+               if (rap->iface != ifp)
+                       continue;
+               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,
+                           sizeof(ap->addr.s6_addr)) == 0)
+                       {
+                               ap->flags |= IPV6_AF_DUPLICATED;
+                               if (ap->dadcallback)
+                                       ap->dadcallback(ap);
+#ifdef DEBUG_NS
+                               found++;
+#endif
+                       }
+               }
+#endif
+       }
+       if (rap == NULL) {
+#ifdef LISTEN_DAD
+               d6state = D6_STATE(ifp);
+               if (d6state) {
+                       TAILQ_FOREACH(ap, &d6state->addrs, next) {
+                               if (memcmp(ap->addr.s6_addr,
+                                   nd_na->nd_na_target.s6_addr,
+                                   sizeof(ap->addr.s6_addr)) == 0)
+                               {
+                                       ap->flags |= IPV6_AF_DUPLICATED;
+                                       if (ap->dadcallback)
+                                               ap->dadcallback(ap);
+#ifdef DEBUG_NS
+                                       found++;
+#endif
+                               }
+                       }
+               }
+#endif
+
+#ifdef DEBUG_NS
+               if (found == 0)
+                       syslog(LOG_DEBUG, "%s: unexpected NA from %s",
+                           ifp->name, sfrom);
+#endif
+               return;
+       }
+
+#ifdef DEBUG_NS
+       syslog(LOG_DEBUG, "%s: %sNA from %s",
+           ifp->name, is_solicited ? "solicited " : "",  sfrom);
+#endif
+
+       /* Node is no longer a router, so remove it from consideration */
+       if (!is_router && !rap->expired) {
+               syslog(LOG_INFO, "%s: %s is no longer a router",
+                   ifp->name, sfrom);
+               rap->expired = 1;
+               ipv6nd_cancelproberouter(rap);
                ipv6_buildroutes();
                script_runreason(ifp, "ROUTERADVERT");
+               return;
+       }
+
+       if (is_solicited && is_router && rap->lifetime) {
+               if (rap->expired) {
+                       rap->expired = 0;
+                       syslog(LOG_INFO, "%s: %s is reachable again",
+                               ifp->name, sfrom);
+                       ipv6_buildroutes();
+                       script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
+               }
+               rap->nsprobes = 0;
+               if (rap->reachable) {
+                       ms_to_tv(&tv, rap->reachable);
+               } else {
+                       tv.tv_sec = REACHABLE_TIME;
+                       tv.tv_usec = 0;
+               }
+               eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap);
+               eloop_timeout_delete(ipv6nd_unreachable, rap);
        }
 }
 
+/* ARGSUSED */
+static void
+ipv6nd_handledata(__unused void *arg)
+{
+       ssize_t len;
+       struct cmsghdr *cm;
+       int hoplimit;
+       struct in6_pktinfo pkt;
+       struct icmp6_hdr *icp;
+       struct interface *ifp;
+
+       len = recvmsg(sock, &rcvhdr, 0);
+       if (len == -1) {
+               syslog(LOG_ERR, "recvmsg: %m");
+               return;
+       }
+       sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
+           ntopbuf, INET6_ADDRSTRLEN);
+       if ((size_t)len < sizeof(struct icmp6_hdr)) {
+               syslog(LOG_ERR, "IPv6 ICMP packet too short from %s", sfrom);
+               return;
+       }
+
+       pkt.ipi6_ifindex = hoplimit = 0;
+       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
+            cm;
+            cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
+       {
+               if (cm->cmsg_level != IPPROTO_IPV6)
+                       continue;
+               switch(cm->cmsg_type) {
+               case IPV6_PKTINFO:
+                       if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
+                               memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
+                       break;
+               case IPV6_HOPLIMIT:
+                       if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
+                               memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
+                       break;
+               }
+       }
+
+       if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
+               syslog(LOG_ERR,
+                   "IPv6 RA did not contain index or hop limit from %s",
+                   sfrom);
+               return;
+       }
+
+       TAILQ_FOREACH(ifp, ifaces, next) {
+               if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
+                       break;
+       }
+
+       icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
+       if (icp->icmp6_code == 0) {
+               switch(icp->icmp6_type) {
+                       case ND_NEIGHBOR_ADVERT:
+                               ipv6nd_handlena(ifp, icp, len);
+                               return;
+                       case ND_ROUTER_ADVERT:
+                               ipv6nd_handlera(ifp, icp, len);
+                               return;
+               }
+       }
+       
+       syslog(LOG_ERR, "invalid IPv6 type %d or code %d from %s",
+           icp->icmp6_type, icp->icmp6_code, sfrom);
+}
+
 int
-ipv6rs_start(struct interface *ifp)
+ipv6nd_startrs(struct interface *ifp)
 {
        struct rs_state *state;
 
        syslog(LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
        if (sock == -1) {
-               if (ipv6rs_open() == -1) {
-                       syslog(LOG_ERR, "%s: ipv6rs_open: %m", __func__);
+               if (ipv6nd_open() == -1) {
+                       syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
                        return -1;
                }
-               eloop_event_add(sock, ipv6rs_handledata, NULL);
+               eloop_event_add(sock, ipv6nd_handledata, NULL);
        }
 
        eloop_timeout_delete(NULL, ifp);
 
        state = RS_STATE(ifp);
        if (state == NULL) {
-               ifp->if_data[IF_DATA_IPV6RS] = calloc(1, sizeof(*state));
+               ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
                state = RS_STATE(ifp);
                if (state == NULL) {
                        syslog(LOG_ERR, "%s: %m", __func__);
@@ -1236,39 +1798,15 @@ ipv6rs_start(struct interface *ifp)
 
        /* Always make a new probe as the underlying hardware
         * address could have changed. */
-       ipv6rs_makeprobe(ifp);
+       ipv6nd_makersprobe(ifp);
        if (state->rs == NULL) {
-               syslog(LOG_ERR, "%s: ipv6rs_makeprobe: %m", __func__);
+               syslog(LOG_ERR, "%s: ipv6ns_makersprobe: %m", __func__);
                return -1;
        }
 
        state->rsprobes = 0;
-       ipv6rs_sendprobe(ifp);
+       ipv6nd_sendrsprobe(ifp);
        return 0;
 }
 
-void
-ipv6rs_drop(struct interface *ifp)
-{
-       struct ra *rap;
-       int expired = 0;
-       TAILQ_HEAD(rahead, ra) rtrs;
 
-       eloop_timeout_delete(NULL, ifp);
-       TAILQ_INIT(&rtrs);
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
-               if (rap->iface == ifp) {
-                       rap->expired = expired = 1;
-                       TAILQ_REMOVE(&ipv6_routers, rap, next);
-                       TAILQ_INSERT_TAIL(&rtrs, rap, next);
-               }
-       }
-       if (expired) {
-               while ((rap = TAILQ_FIRST(&rtrs))) {
-                       TAILQ_REMOVE(&rtrs, rap, next);
-                       ipv6rs_drop_ra(rap);
-               }
-               ipv6_buildroutes();
-               script_runreason(ifp, "ROUTERADVERT");
-       }
-}
similarity index 65%
rename from ipv6rs.h
rename to ipv6nd.h
index 4aa752161f87dacd6914ccc760e40e38b9eda9e3..b904628601628fd1f8d79931fcbc89e37036e2b6 100644 (file)
--- a/ipv6rs.h
+++ b/ipv6nd.h
@@ -25,8 +25,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef IPV6RS_H
-#define IPV6RS_H
+#ifndef IPV6ND_H
+#define IPV6ND_H
 
 #include <sys/queue.h>
 
@@ -73,26 +73,43 @@ struct rs_state {
        int rsprobes;
 };
 
-#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6RS])
+#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
+
+#define MAX_REACHABLE_TIME     3600    /* seconds */
+#define REACHABLE_TIME         30      /* seconds */
+#define RETRANS_TIMER          1000    /* milliseconds */
+#define DELAY_FIRST_PROBE_TIME 5       /* seconds */
 
 #ifdef INET6
-int ipv6rs_start(struct interface *);
-ssize_t ipv6rs_env(char **, const char *, const struct interface *);
-const struct ipv6_addr * ipv6rs_findprefix(const struct ipv6_addr *);
-int ipv6rs_addrexists(const struct ipv6_addr *);
-void ipv6rs_freedrop_ra(struct ra *, int);
-#define ipv6rs_free_ra(ra) ipv6rs_freedrop_ra((ra),  0)
-#define ipv6rs_drop_ra(ra) ipv6rs_freedrop_ra((ra),  1)
-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 *, int);
-void ipv6rs_drop(struct interface *);
+int ipv6nd_startrs(struct interface *);
+ssize_t ipv6nd_env(char **, const char *, const struct interface *);
+const struct ipv6_addr * ipv6nd_findprefix(const struct ipv6_addr *);
+int ipv6nd_addrexists(const struct ipv6_addr *);
+void ipv6nd_freedrop_ra(struct ra *, int);
+#define ipv6nd_free_ra(ra) ipv6nd_freedrop_ra((ra),  0)
+#define ipv6nd_drop_ra(ra) ipv6nd_freedrop_ra((ra),  1)
+ssize_t ipv6nd_free(struct interface *);
+void ipv6nd_expirera(void *arg);
+int ipv6nd_has_ra(const struct interface *);
+void ipv6nd_handleifa(int, const char *, const struct in6_addr *, int);
+void ipv6nd_drop(struct interface *);
+
+void ipv6nd_probeaddr(void *);
+ssize_t ipv6nd_probeaddrs(struct ipv6_addrhead *);
+void ipv6nd_proberouter(void *);
+void ipv6nd_cancelproberouter(struct ra *);
+
+#ifdef LISTEN_DAD
+void ipv6nd_cancelprobeaddr(struct ipv6_addr *);
+#else
+#define ipv6nd_cancelprobeaddr(a)
+#endif
+
 #else
-#define ipv6rs_start(a) {}
-#define ipv6rs_free(a)
-#define ipv6rs_has_ra(a) 0
-#define ipv6rs_drop(a)
+#define ipv6nd_startrs(a) {}
+#define ipv6nd_free(a)
+#define ipv6nd_has_ra(a) 0
+#define ipv6nd_drop(a)
 #endif
 
 #endif
diff --git a/ipv6ns.c b/ipv6ns.c
deleted file mode 100644 (file)
index 6c02e58..0000000
--- a/ipv6ns.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
- * All rights reserved
-
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#ifdef __linux__
-#  define _LINUX_IN6_H
-#  include <linux/ipv6.h>
-#endif
-
-#define ELOOP_QUEUE 2
-#include "common.h"
-#include "dhcpcd.h"
-#include "dhcp6.h"
-#include "eloop.h"
-#include "ipv6.h"
-#include "ipv6ns.h"
-#include "script.h"
-
-#define MIN_RANDOM_FACTOR      500                             /* millisecs */
-#define MAX_RANDOM_FACTOR      1500                            /* millisecs */
-#define MIN_RANDOM_FACTOR_U    MIN_RANDOM_FACTOR * 1000        /* usecs */
-#define MAX_RANDOM_FACTOR_U    MAX_RANDOM_FACTOR * 1000        /* usecs */
-
-#if BYTE_ORDER == BIG_ENDIAN
-#define IPV6_ADDR_INT32_ONE     1
-#define IPV6_ADDR_INT16_MLL     0xff02
-#elif BYTE_ORDER == LITTLE_ENDIAN
-#define IPV6_ADDR_INT32_ONE     0x01000000
-#define IPV6_ADDR_INT16_MLL     0x02ff
-#endif
-
-/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
-//#define DEBUG_NS
-//
-
-/* Currently, no known kernel allows us to send from the unspecified address
- * which is required for DAD to work. This isn't that much of a problem as
- * the kernel will do DAD for us correctly, however we don't know the exact
- * randomness the kernel applies to the timeouts. So we just follow the same
- * logic and have a little faith.
- * This define is purely for completeness */
-// #define IPV6_SEND_DAD
-
-static int sock = -1;
-#ifdef IPV6_SEND_DAD
-static int unspec_sock = -1;
-#endif
-static struct sockaddr_in6 from;
-static struct msghdr sndhdr;
-static struct iovec sndiov[2];
-static unsigned char *sndbuf;
-static struct msghdr rcvhdr;
-static struct iovec rcviov[2];
-static unsigned char *rcvbuf;
-static unsigned char ansbuf[1500];
-static char ntopbuf[INET6_ADDRSTRLEN];
-
-static void ipv6ns_handledata(__unused void *arg);
-
-#if DEBUG_MEMORY
-static void
-ipv6ns_cleanup(void)
-{
-
-       free(sndbuf);
-       free(rcvbuf);
-}
-#endif
-
-static int
-ipv6ns_open(void)
-{
-       int on;
-       int len;
-       struct icmp6_filter filt;
-#ifdef IPV6_SEND_DAD
-       union {
-               struct sockaddr sa;
-               struct sockaddr_in6 sin;
-       } su;
-#endif
-
-       if (sock != -1)
-               return sock;
-
-       sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
-       if (sock == -1)
-               return -1;
-       on = 1;
-       if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
-           &on, sizeof(on)) == -1)
-               goto eexit;
-
-       on = 1;
-       if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
-           &on, sizeof(on)) == -1)
-               goto eexit;
-
-       ICMP6_FILTER_SETBLOCKALL(&filt);
-
-#ifdef IPV6_SEND_DAD
-       /* We send DAD requests from the unspecified address. */
-       unspec_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
-       if (unspec_sock == -1)
-               goto eexit;
-       if (setsockopt(unspec_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
-           &filt, sizeof(filt)) == -1)
-               goto eexit;
-       memset(&su, 0, sizeof(su));
-       su.sin.sin6_family = AF_INET6;
-#ifdef SIN6_LEN
-       su.sin.sin6_len = sizeof(su.sin);
-#endif
-       if (bind(unspec_sock, &su.sa, sizeof(su.sin)) == -1)
-               goto eexit;
-#endif
-
-       ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
-       if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
-           &filt, sizeof(filt)) == -1)
-               goto eexit;
-
-       set_cloexec(sock);
-#if DEBUG_MEMORY
-       atexit(ipv6ns_cleanup);
-#endif
-
-#ifdef LISTEN_DAD
-       syslog(LOG_WARNING, "kernel does not report DAD results to userland");
-       syslog(LOG_WARNING,
-           "warning listening to duplicated addresses on the wire");
-#endif
-
-       len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
-       sndbuf = calloc(1, len);
-       if (sndbuf == NULL)
-               goto eexit;
-       sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
-       sndhdr.msg_iov = sndiov;
-       sndhdr.msg_iovlen = 1;
-       sndhdr.msg_control = sndbuf;
-       sndhdr.msg_controllen = len;
-       rcvbuf = calloc(1, len);
-       if (rcvbuf == NULL)
-               goto eexit;
-       rcvhdr.msg_name = &from;
-       rcvhdr.msg_namelen = sizeof(from);
-       rcvhdr.msg_iov = rcviov;
-       rcvhdr.msg_iovlen = 1;
-       rcvhdr.msg_control = rcvbuf;
-       rcvhdr.msg_controllen = len;
-       rcviov[0].iov_base = ansbuf;
-       rcviov[0].iov_len = sizeof(ansbuf);
-
-       eloop_event_add(sock, ipv6ns_handledata, NULL);
-       return sock;
-
-eexit:
-       syslog(LOG_ERR, "%s: %m", __func__);
-       close(sock);
-       sock = -1;
-       free(sndbuf);
-       sndbuf = NULL;
-       free(rcvbuf);
-       rcvbuf = NULL;
-       return -1;
-}
-
-static void
-ipv6ns_unreachable(void *arg)
-{
-       struct ra *rap = arg;
-       struct timeval tv;
-
-       /* We could add an unreachable flag and persist the information,
-        * but that is more effort than it's probably worth. */
-       syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
-           rap->iface->name, rap->sfrom);
-       rap->expired = 1;
-       ipv6_buildroutes();
-       script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
-
-       /* We should still test if it's reachable or not so
-        * incase it comes back to life and it's preferable. */
-       if (rap->reachable) {
-               ms_to_tv(&tv, rap->reachable);
-       } else {
-               tv.tv_sec = REACHABLE_TIME;
-               tv.tv_usec = 0;
-       }
-       eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap);
-}
-
-#ifdef LISTEN_DAD
-void
-ipv6ns_cancelprobeaddr(struct ipv6_addr *ap)
-{
-
-       eloop_timeout_delete(ipv6ns_probeaddr, ap);
-       if (ap->dadcallback)
-               eloop_timeout_delete(ap->dadcallback, ap);
-}
-#endif
-
-void
-ipv6ns_probeaddr(void *arg)
-{
-       struct ipv6_addr *ap = arg;
-#ifdef IPV6_SEND_DAD
-       struct nd_neighbor_solicit *ns;
-       struct nd_opt_hdr *nd;
-       struct sockaddr_in6 dst;
-       struct cmsghdr *cm;
-       struct in6_pktinfo pi;
-       int hoplimit = HOPLIMIT;
-#else
-#ifdef LISTEN_DAD
-       struct timeval tv, rtv;
-       struct timeval mtv;
-       int i;
-#endif
-#endif
-
-       if (ap->dadcallback &&
-           ((ap->flags & IPV6_AF_NEW) == 0 ||
-           ap->nsprobes >= ap->iface->options->dadtransmits))
-       {
-#ifdef IPV6_SEND_DAD
-               ap->dadcallback(ap);
-#else
-               ipv6_addaddr(ap);
-#endif
-               return;
-       }
-
-       if (ipv6ns_open() == -1)
-               return;
-
-       ap->flags &= ~IPV6_AF_DADCOMPLETED;
-
-#ifdef IPV6_SEND_DAD
-       if (!ap->ns) {
-               ap->nslen = sizeof(*ns) + ROUNDUP8(ap->iface->hwlen + 2);
-               ap->ns = calloc(1, ap->nslen);
-               if (ap->ns == NULL) {
-                       syslog(LOG_ERR, "%s: %m", __func__);
-                       return;
-               }
-               ns = (struct nd_neighbor_solicit *)(void *)ap->ns;
-               ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
-               //ns->nd_ns_cksum = 0;
-               //ns->nd_ns_code = 0;
-               //ns->nd_ns_reserved = 0;
-               ns->nd_ns_target = ap->addr;
-               nd = (struct nd_opt_hdr *)(ap->ns + sizeof(*ns));
-               nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-               nd->nd_opt_len = (ROUNDUP8(ap->iface->hwlen + 2)) >> 3;
-               memcpy(nd + 1, ap->iface->hwaddr, ap->iface->hwlen);
-       }
-
-       memset(&dst, 0, sizeof(dst));
-       dst.sin6_family = AF_INET6;
-#ifdef SIN6_LEN
-       dst.sin6_len = sizeof(dst);
-#endif
-       dst.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
-       dst.sin6_addr.s6_addr16[1] = 0;
-       dst.sin6_addr.s6_addr32[1] = 0;
-       dst.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
-       dst.sin6_addr.s6_addr32[3] = ap->addr.s6_addr32[3];
-       dst.sin6_addr.s6_addr[12] = 0xff;
-
-       //memcpy(&dst.sin6_addr, &ap->addr, sizeof(dst.sin6_addr));
-       dst.sin6_scope_id = ap->iface->index;
-
-       sndhdr.msg_name = (caddr_t)&dst;
-       sndhdr.msg_iov[0].iov_base = ap->ns;
-       sndhdr.msg_iov[0].iov_len = ap->nslen;
-
-       /* Set the outbound interface */
-       cm = CMSG_FIRSTHDR(&sndhdr);
-       cm->cmsg_level = IPPROTO_IPV6;
-       cm->cmsg_type = IPV6_PKTINFO;
-       cm->cmsg_len = CMSG_LEN(sizeof(pi));
-       memset(&pi, 0, sizeof(pi));
-       pi.ipi6_ifindex = ap->iface->index;
-       memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
-
-       /* Hop limit */
-       cm = CMSG_NXTHDR(&sndhdr, cm);
-       cm->cmsg_level = IPPROTO_IPV6;
-       cm->cmsg_type = IPV6_HOPLIMIT;
-       cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
-       memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
-
-#ifdef DEBUG_NS
-       syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
-           ap->iface->name, ap->saddr);
-       if (ap->dadcallback == NULL)
-               syslog(LOG_WARNING, "%s: no callback!", ap->iface->name);
-#endif
-       if (sendmsg(unspec_sock, &sndhdr, 0) == -1) {
-               syslog(LOG_ERR, "%s: %s: sendmsg: %m",
-                   ap->iface->name, __func__);
-               return;
-       }
-
-       if (ap->dadcallback) {
-               ms_to_tv(&tv, RETRANS_TIMER);
-               ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
-               timeradd(&tv, &rtv, &tv);
-               rtv.tv_sec = 0;
-               rtv.tv_usec = arc4random() %
-                   (MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
-               timeradd(&tv, &rtv, &tv);
-
-               eloop_timeout_add_tv(&tv,
-                   ++(ap->nsprobes) < ap->iface->options->dadtransmits ?
-                   ipv6ns_probeaddr : ap->dadcallback,
-                   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 */
-       if (ap->dadcallback) {
-               mtv.tv_sec = 0;
-               mtv.tv_usec = 0;
-               for (i = 0; i < ap->iface->options->dadtransmits; i++) {
-                       ms_to_tv(&tv, RETRANS_TIMER);
-                       ms_to_tv(&rtv, MAX_RANDOM_FACTOR);
-                       timeradd(&tv, &rtv, &tv);
-                       timeradd(&mtv, &tv, &mtv);
-               }
-               eloop_timeout_add_tv(&mtv, ap->dadcallback, ap);
-       }
-#endif
-#endif /* IPV6_SEND_DAD */
-}
-
-ssize_t
-ipv6ns_probeaddrs(struct ipv6_addrhead *addrs)
-{
-       struct ipv6_addr *ap, *apn;
-       ssize_t i;
-
-       i = 0;
-       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);
-                               i++;
-                       }
-                       if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
-                           del_address6(ap) == -1 &&
-                           errno != EADDRNOTAVAIL && errno != ENXIO)
-                               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;
-}
-
-void
-ipv6ns_proberouter(void *arg)
-{
-       struct ra *rap = arg;
-       struct nd_neighbor_solicit *ns;
-       struct nd_opt_hdr *nd;
-       struct sockaddr_in6 dst;
-       struct cmsghdr *cm;
-       struct in6_pktinfo pi;
-       int hoplimit = HOPLIMIT;
-       struct timeval tv, rtv;
-
-       if (ipv6ns_open() == -1)
-               return;
-
-       if (!rap->ns) {
-               rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
-               rap->ns = calloc(1, rap->nslen);
-               if (rap->ns == NULL) {
-                       syslog(LOG_ERR, "%s: %m", __func__);
-                       return;
-               }
-               ns = (struct nd_neighbor_solicit *)(void *)rap->ns;
-               ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
-               //ns->nd_ns_cksum = 0;
-               //ns->nd_ns_code = 0;
-               //ns->nd_ns_reserved = 0;
-               ns->nd_ns_target = rap->from;
-               nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns));
-               nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-               nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3;
-               memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen);
-       }
-
-       memset(&dst, 0, sizeof(dst));
-       dst.sin6_family = AF_INET6;
-#ifdef SIN6_LEN
-       dst.sin6_len = sizeof(dst);
-#endif
-       memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr));
-       dst.sin6_scope_id = rap->iface->index;
-
-       sndhdr.msg_name = (caddr_t)&dst;
-       sndhdr.msg_iov[0].iov_base = rap->ns;
-       sndhdr.msg_iov[0].iov_len = rap->nslen;
-
-       /* Set the outbound interface */
-       cm = CMSG_FIRSTHDR(&sndhdr);
-       cm->cmsg_level = IPPROTO_IPV6;
-       cm->cmsg_type = IPV6_PKTINFO;
-       cm->cmsg_len = CMSG_LEN(sizeof(pi));
-       memset(&pi, 0, sizeof(pi));
-       pi.ipi6_ifindex = rap->iface->index;
-       memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
-
-       /* Hop limit */
-       cm = CMSG_NXTHDR(&sndhdr, cm);
-       cm->cmsg_level = IPPROTO_IPV6;
-       cm->cmsg_type = IPV6_HOPLIMIT;
-       cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
-       memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
-
-#ifdef DEBUG_NS
-       syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
-           rap->iface->name, rap->sfrom);
-#endif
-       if (sendmsg(sock, &sndhdr, 0) == -1) {
-               syslog(LOG_ERR, "%s: %s: sendmsg: %m",
-                   rap->iface->name, __func__);
-               return;
-       }
-
-       ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans);
-       ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
-       timeradd(&tv, &rtv, &tv);
-       rtv.tv_sec = 0;
-       rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U);
-       timeradd(&tv, &rtv, &tv);
-       eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap);
-
-       if (rap->nsprobes++ == 0)
-               eloop_timeout_add_sec(DELAY_FIRST_PROBE_TIME,
-                   ipv6ns_unreachable, rap);
-}
-
-void
-ipv6ns_cancelproberouter(struct ra *rap)
-{
-
-       eloop_timeout_delete(ipv6ns_proberouter, rap);
-       eloop_timeout_delete(ipv6ns_unreachable, rap);
-}
-
-/* ARGSUSED */
-static void
-ipv6ns_handledata(__unused void *arg)
-{
-       ssize_t len;
-       struct cmsghdr *cm;
-       int hoplimit;
-       struct in6_pktinfo pkt;
-       struct icmp6_hdr *icp;
-       struct interface *ifp;
-       const char *sfrom;
-       struct nd_neighbor_advert *nd_na;
-       struct ra *rap;
-       int is_router, is_solicited;
-#ifdef DEBUG_NS
-       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) {
-               syslog(LOG_ERR, "recvmsg: %m");
-               return;
-       }
-       sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
-           ntopbuf, INET6_ADDRSTRLEN);
-       if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
-               syslog(LOG_ERR, "IPv6 NA packet too short from %s", sfrom);
-               return;
-       }
-
-       pkt.ipi6_ifindex = hoplimit = 0;
-       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
-            cm;
-            cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
-       {
-               if (cm->cmsg_level != IPPROTO_IPV6)
-                       continue;
-               switch(cm->cmsg_type) {
-               case IPV6_PKTINFO:
-                       if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
-                               memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
-                       break;
-               case IPV6_HOPLIMIT:
-                       if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
-                               memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
-                       break;
-               }
-       }
-
-       if (pkt.ipi6_ifindex == 0 || hoplimit != 255) {
-               syslog(LOG_ERR,
-                   "IPv6 NA did not contain index or hop limit from %s",
-                   sfrom);
-               return;
-       }
-
-       icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
-       if (icp->icmp6_type != ND_NEIGHBOR_ADVERT ||
-           icp->icmp6_code != 0)
-       {
-               syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom);
-               return;
-       }
-
-       TAILQ_FOREACH(ifp, ifaces, next) {
-               if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
-                       break;
-       }
-       if (ifp == NULL) {
-#ifdef DEBUG_NS
-               syslog(LOG_DEBUG, "NA for unexpected interface from %s", sfrom);
-#endif
-               return;
-       }
-
-       nd_na = (struct nd_neighbor_advert *)icp;
-       is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
-       is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
-
-       if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
-               syslog(LOG_ERR, "%s: NA for multicast address from %s",
-                   ifp->name, sfrom);
-               return;
-       }
-
-#ifdef DEBUG_NS
-       found = 0;
-#endif
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
-               if (rap->iface != ifp)
-                       continue;
-               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,
-                           sizeof(ap->addr.s6_addr)) == 0)
-                       {
-                               ap->flags |= IPV6_AF_DUPLICATED;
-                               if (ap->dadcallback)
-                                       ap->dadcallback(ap);
-#ifdef DEBUG_NS
-                               found++;
-#endif
-                       }
-               }
-#endif
-       }
-       if (rap == NULL) {
-#ifdef LISTEN_DAD
-               d6state = D6_STATE(ifp);
-               if (d6state) {
-                       TAILQ_FOREACH(ap, &d6state->addrs, next) {
-                               if (memcmp(ap->addr.s6_addr,
-                                   nd_na->nd_na_target.s6_addr,
-                                   sizeof(ap->addr.s6_addr)) == 0)
-                               {
-                                       ap->flags |= IPV6_AF_DUPLICATED;
-                                       if (ap->dadcallback)
-                                               ap->dadcallback(ap);
-#ifdef DEBUG_NS
-                                       found++;
-#endif
-                               }
-                       }
-               }
-#endif
-
-#ifdef DEBUG_NS
-               if (found == 0)
-                       syslog(LOG_DEBUG, "%s: unexpected NA from %s",
-                           ifp->name, sfrom);
-#endif
-               return;
-       }
-
-#ifdef DEBUG_NS
-       syslog(LOG_DEBUG, "%s: %sNA from %s",
-           ifp->name, is_solicited ? "solicited " : "",  sfrom);
-#endif
-
-       /* Node is no longer a router, so remove it from consideration */
-       if (!is_router && !rap->expired) {
-               syslog(LOG_INFO, "%s: %s is no longer a router",
-                   ifp->name, sfrom);
-               rap->expired = 1;
-               ipv6ns_cancelproberouter(rap);
-               ipv6_buildroutes();
-               script_runreason(ifp, "ROUTERADVERT");
-               return;
-       }
-
-       if (is_solicited && is_router && rap->lifetime) {
-               if (rap->expired) {
-                       rap->expired = 0;
-                       syslog(LOG_INFO, "%s: %s is reachable again",
-                               ifp->name, sfrom);
-                       ipv6_buildroutes();
-                       script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
-               }
-               rap->nsprobes = 0;
-               if (rap->reachable) {
-                       ms_to_tv(&tv, rap->reachable);
-               } else {
-                       tv.tv_sec = REACHABLE_TIME;
-                       tv.tv_usec = 0;
-               }
-               eloop_timeout_add_tv(&tv, ipv6ns_proberouter, rap);
-               eloop_timeout_delete(ipv6ns_unreachable, rap);
-       }
-}
diff --git a/ipv6ns.h b/ipv6ns.h
deleted file mode 100644 (file)
index eca6108..0000000
--- a/ipv6ns.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
- * All rights reserved
-
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef IPV6NS_H
-#define IPV6NS_H
-
-#include "dhcpcd.h"
-#include "ipv6rs.h"
-
-#define MAX_REACHABLE_TIME     3600    /* seconds */
-#define REACHABLE_TIME         30      /* seconds */
-#define RETRANS_TIMER          1000    /* milliseconds */
-#define DELAY_FIRST_PROBE_TIME 5       /* seconds */
-
-void ipv6ns_probeaddr(void *);
-ssize_t ipv6ns_probeaddrs(struct ipv6_addrhead *);
-void ipv6ns_proberouter(void *);
-void ipv6ns_cancelproberouter(struct ra *);
-
-#ifdef LISTEN_DAD
-void ipv6ns_cancelprobeaddr(struct ipv6_addr *);
-#else
-#define ipv6ns_cancelprobeaddr(a)
-#endif
-#endif
diff --git a/net.c b/net.c
index 92a9b18cb862c2366563b136516b77675e5bb37a..898b222157ea68602b21116f29b39b9fa8301c07 100644 (file)
--- a/net.c
+++ b/net.c
@@ -70,7 +70,7 @@
 #include "dhcp.h"
 #include "dhcp6.h"
 #include "if-options.h"
-#include "ipv6rs.h"
+#include "ipv6nd.h"
 #include "net.h"
 
 int socket_afnet = -1;
@@ -141,7 +141,7 @@ free_interface(struct interface *ifp)
        dhcp_free(ifp);
        ipv6_free(ifp);
        dhcp6_free(ifp);
-       ipv6rs_free(ifp);
+       ipv6nd_free(ifp);
        free_options(ifp->options);
        free(ifp);
 }
index 80dfaa2fdcb6b7cf008ed8ee91b60767b21f6aba..3bdab5deef737f6b168be0f6621f794417b48cb6 100644 (file)
--- a/script.c
+++ b/script.c
@@ -48,7 +48,7 @@
 #include "dhcp6.h"
 #include "if-options.h"
 #include "if-pref.h"
-#include "ipv6rs.h"
+#include "ipv6nd.h"
 #include "net.h"
 #include "script.h"
 
@@ -214,7 +214,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
 #ifdef INET6
                if (d6_state && d6_state->new)
                        dhcp6 = 1;
-               else if (ipv6rs_has_ra(ifp))
+               else if (ipv6nd_has_ra(ifp))
                        ra = 1;
                else
 #endif
@@ -280,7 +280,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        } else if ((dhcp && state && state->new)
 #ifdef INET6
            || (dhcp6 && d6_state && d6_state->new)
-           || (ra && ipv6rs_has_ra(ifp))
+           || (ra && ipv6nd_has_ra(ifp))
 #endif
            )
        {
@@ -389,13 +389,13 @@ dumplease:
                }
        }
        if (ra) {
-               e = ipv6rs_env(NULL, NULL, ifp);
+               e = ipv6nd_env(NULL, NULL, ifp);
                if (e > 0) {
                        nenv = realloc(env, sizeof(char *) * (elen + e + 1));
                        if (nenv == NULL)
                                goto eexit;
                        env = nenv;
-                       l = ipv6rs_env(env + elen, NULL, ifp);
+                       l = ipv6nd_env(env + elen, NULL, ifp);
                        if (l == -1)
                                goto eexit;
                        elen += l;
@@ -478,7 +478,7 @@ send_interface(int fd, const struct interface *iface)
 #endif
 
 #ifdef INET6
-       if (ipv6rs_has_ra(iface)) {
+       if (ipv6nd_has_ra(iface)) {
                onestate = 1;
                if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
                        retval = -1;