]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Instead of opening link, ipv6, ipv6rs and ipv6ns sockets globally,
authorRoy Marples <roy@marples.name>
Fri, 15 Feb 2013 20:33:13 +0000 (20:33 +0000)
committerRoy Marples <roy@marples.name>
Fri, 15 Feb 2013 20:33:13 +0000 (20:33 +0000)
only open when the first link wanting this features needs it.
Hopefully fixes #263 and #264.

dhcpcd.c
ipv6.c
ipv6ns.c
ipv6rs.c

index 2db1924cce31d580de5c76a37cb744bdd3127709..d2a7b87558d3ef0613dd82983345f60a1936089d 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -453,16 +453,45 @@ start_interface(void *arg)
                dhcp_start(ifp);
 }
 
+/* ARGSUSED */
+static void
+handle_link(_unused void *arg)
+{
+
+       if (manage_link(linkfd) == -1)
+               syslog(LOG_ERR, "manage_link: %m");
+}
+
 static void
 init_state(struct interface *ifp, int argc, char **argv)
 {
+       struct if_options *ifo;
        const char *reason = NULL;
 
        configure_interface(ifp, argc, argv);
+       ifo = ifp->options;
+
+       if (if_options->options & DHCPCD_LINK && linkfd == -1) {
+               linkfd = open_link_socket();
+               if (linkfd == -1) {
+                       syslog(LOG_ERR, "open_link_socket: %m");
+                       ifo->options &= ~DHCPCD_LINK;
+               } else
+                       eloop_event_add(linkfd, handle_link, NULL);
+       }
+
+       if (ifo->options & DHCPCD_IPV6RS && !check_ipv6(NULL))
+               ifo->options &= ~DHCPCD_IPV6RS;
+       if (ifo->options & DHCPCD_IPV6RS && ipv6_init() == -1) {
+               ifo->options &= ~DHCPCD_IPV6RS;
+               syslog(LOG_ERR, "ipv6_init: %m");
+       }
+
+
        if (!(options & DHCPCD_TEST))
                script_runreason(ifp, "PREINIT");
 
-       if (ifp->options->options & DHCPCD_LINK) {
+       if (ifo->options & DHCPCD_LINK) {
                switch (carrier_status(ifp)) {
                case 0:
                        ifp->carrier = LINK_DOWN;
@@ -573,15 +602,6 @@ handle_hwaddr(const char *ifname, unsigned char *hwaddr, size_t hwlen)
 }
 #endif
 
-/* ARGSUSED */
-static void
-handle_link(_unused void *arg)
-{
-
-       if (manage_link(linkfd) == -1)
-               syslog(LOG_ERR, "manage_link: %m");
-}
-
 static void
 if_reboot(struct interface *ifp, int argc, char **argv)
 {
@@ -1105,13 +1125,6 @@ main(int argc, char **argv)
                syslog(LOG_ERR, "open_sockets: %m");
                exit(EXIT_FAILURE);
        }
-       if (if_options->options & DHCPCD_LINK) {
-               linkfd = open_link_socket();
-               if (linkfd == -1)
-                       syslog(LOG_ERR, "open_link_socket: %m");
-               else
-                       eloop_event_add(linkfd, handle_link, NULL);
-       }
 
 #if 0
        if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) {
@@ -1120,15 +1133,6 @@ main(int argc, char **argv)
        }
 #endif
 
-       if (options & DHCPCD_IPV6 && ipv6_init() == -1) {
-               options &= ~DHCPCD_IPV6;
-               syslog(LOG_ERR, "ipv6_init: %m");
-       }
-       if (options & DHCPCD_IPV6RS && !check_ipv6(NULL))
-               options &= ~DHCPCD_IPV6RS;
-       if (options & DHCPCD_IPV6RS)
-               ipv6rs_init();
-
        ifc = argc - optind;
        ifv = argv + optind;
 
diff --git a/ipv6.c b/ipv6.c
index 03a8dc169e808b44671f17633301b47748320172..fc15883d9297195197ef73e95e3fea7aaad21d7c 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -35,6 +35,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
+#include <unistd.h>
 
 #include "common.h"
 #include "dhcpcd.h"
@@ -66,14 +67,15 @@ ipv6_cleanup()
 int ipv6_init(void)
 {
 
-       routes = malloc(sizeof(*routes));
-       if (routes == NULL)
-               return -1;
-
-       TAILQ_INIT(routes);
+       if (routes == NULL) {
+               routes = malloc(sizeof(*routes));
+               if (routes == NULL) 
+                       return -1;
+               TAILQ_INIT(routes);
 #ifdef DEBUG_MEMORY
-       atexit(ipv6_cleanup);
+               atexit(ipv6_cleanup);
 #endif
+       }
        return 0;
 }
 
index 62dde8787d9ac4329d9c5c6008c86b497ac426a2..c98a2cfaedddac1979450c6417d8c6f7d03447d1 100644 (file)
--- a/ipv6ns.c
+++ b/ipv6ns.c
@@ -39,6 +39,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
+#include <unistd.h>
 
 #ifdef __linux__
 #  define _LINUX_IN6_H
@@ -59,7 +60,7 @@
 /* Debugging Neighbor Solicitations is a lot of spam, so disable it */
 //#define DEBUG_NS
 
-static int sock;
+static int sock = -1;
 static struct sockaddr_in6 from;
 static struct msghdr sndhdr;
 static struct iovec sndiov[2];
@@ -70,6 +71,8 @@ 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)
@@ -92,19 +95,19 @@ ipv6ns_open(void)
                return -1;
        on = 1;
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
-               &on, sizeof(on)) == -1)
-               return -1;
+           &on, sizeof(on)) == -1)
+               goto eexit;
 
        on = 1;
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
-               &on, sizeof(on)) == -1)
-               return -1;
+           &on, sizeof(on)) == -1)
+               goto eexit;
 
        ICMP6_FILTER_SETBLOCKALL(&filt);
        ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
        if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
-               &filt, sizeof(filt)) == -1)
-               return -1;
+           &filt, sizeof(filt)) == -1)
+               goto eexit;
 
        set_cloexec(sock);
 #if DEBUG_MEMORY
@@ -112,17 +115,17 @@ ipv6ns_open(void)
 #endif
 
        len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
-       sndbuf = xzalloc(len);
+       sndbuf = calloc(1, len);
        if (sndbuf == NULL)
-               return -1;
+               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 = xzalloc(len);
+       rcvbuf = calloc(1, len);
        if (rcvbuf == NULL)
-               return -1;
+               goto eexit;
        rcvhdr.msg_name = &from;
        rcvhdr.msg_namelen = sizeof(from);
        rcvhdr.msg_iov = rcviov;
@@ -132,6 +135,15 @@ ipv6ns_open(void)
        rcviov[0].iov_base = ansbuf;
        rcviov[0].iov_len = sizeof(ansbuf);
        return sock;
+
+eexit:
+       close(sock);
+       sock = -1;
+       free(sndbuf);
+       sndbuf = NULL;
+       free(rcvbuf);
+       rcvbuf = NULL;
+       return -1;
 }
 
 static int
@@ -142,7 +154,7 @@ ipv6ns_makeprobe(struct ra *rap)
 
        free(rap->ns);
        rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
-       rap->ns = xzalloc(rap->nslen);
+       rap->ns = calloc(1, rap->nslen);
        if (rap->ns == NULL)
                return -1;
        ns = (struct nd_neighbor_solicit *)(void *)rap->ns;
@@ -182,9 +194,17 @@ ipv6ns_sendprobe(void *arg)
        int hoplimit = HOPLIMIT;
        struct timeval tv, rtv;
 
-       if (!rap->ns) {
-               if (ipv6ns_makeprobe(rap) == -1)
+       if (sock == -1) {
+               if (ipv6ns_open() == -1) {
+                       syslog(LOG_ERR, "%s: ipv6ns_open: %m", __func__);
                        return;
+               }
+               eloop_event_add(sock, ipv6ns_handledata, NULL);
+       }
+
+       if (!rap->ns && ipv6ns_makeprobe(rap) == -1) {
+               syslog(LOG_ERR, "%s: ipv6ns_makeprobe: %m", __func__);
+               return;
        }
 
        memset(&dst, 0, sizeof(dst));
@@ -220,7 +240,8 @@ ipv6ns_sendprobe(void *arg)
            rap->iface->name, rap->sfrom);
 #endif
        if (sendmsg(sock, &sndhdr, 0) == -1)
-               syslog(LOG_ERR, "%s: sendmsg: %m", rap->iface->name);
+               syslog(LOG_ERR, "%s: %s: sendmsg: %m",
+                   __func__, rap->iface->name);
 
 
        ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans);
index 8193fa00e4591651af83f6aa7adbed3c64498bf2..ac30346c5c13bb0741c15060a609f57856fc0ea0 100644 (file)
--- a/ipv6rs.c
+++ b/ipv6rs.c
@@ -43,6 +43,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
+#include <unistd.h>
 
 #define ELOOP_QUEUE 1
 #include "common.h"
@@ -104,7 +105,7 @@ struct nd_opt_dnssl {               /* DNSSL option RFC 6106 */
 
 struct rahead ipv6_routers = TAILQ_HEAD_INITIALIZER(ipv6_routers);
 
-static int sock;
+static int sock = -1;
 static struct sockaddr_in6 allrouters, from;
 static struct msghdr sndhdr;
 static struct iovec sndiov[2];
@@ -132,31 +133,32 @@ ipv6rs_open(void)
        int len;
        struct icmp6_filter filt;
 
+       sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+       if (sock == -1)
+               return -1;
+
        memset(&allrouters, 0, sizeof(allrouters));
        allrouters.sin6_family = AF_INET6;
 #ifdef SIN6_LEN
        allrouters.sin6_len = sizeof(allrouters);
 #endif
        if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1)
-               return -1;
-       sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
-       if (sock == -1)
-               return -1;
+               goto eexit;
        on = 1;
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                &on, sizeof(on)) == -1)
-               return -1;
+               goto eexit;
 
        on = 1;
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
                &on, sizeof(on)) == -1)
-               return -1;
+               goto eexit;
 
        ICMP6_FILTER_SETBLOCKALL(&filt);
        ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
        if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
                &filt, sizeof(filt)) == -1)
-               return -1;
+               goto eexit;
 
        set_cloexec(sock);
 #if DEBUG_MEMORY
@@ -164,17 +166,17 @@ ipv6rs_open(void)
 #endif
 
        len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
-       sndbuf = xzalloc(len);
+       sndbuf = calloc(1, len);
        if (sndbuf == NULL)
-               return -1;
+               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 = xzalloc(len);
+       rcvbuf = calloc(1, len);
        if (rcvbuf == NULL)
-               return -1;
+               goto eexit;
        rcvhdr.msg_name = &from;
        rcvhdr.msg_namelen = sizeof(from);
        rcvhdr.msg_iov = rcviov;
@@ -184,6 +186,15 @@ ipv6rs_open(void)
        rcviov[0].iov_base = ansbuf;
        rcviov[0].iov_len = sizeof(ansbuf);
        return sock;
+
+eexit:
+       close(sock);
+       sock = -1;
+       free(sndbuf);
+       sndbuf = NULL;
+       free(rcvbuf);
+       rcvbuf = NULL;
+       return -1;
 }
 
 static int
@@ -786,8 +797,8 @@ ipv6rs_handledata(_unused void *arg)
 
        /* If we're owning the RA then we need to try and ensure the
         * router is actually reachable */
-       if (options & DHCPCD_IPV6RA_OWN ||
-           options & DHCPCD_IPV6RA_OWN_DEFAULT)
+       if (ifp->options->options & DHCPCD_IPV6RA_OWN ||
+           ifp->options->options & DHCPCD_IPV6RA_OWN_DEFAULT)
        {
                rap->nsprobes = 0;
                ipv6ns_sendprobe(rap);
@@ -1085,19 +1096,33 @@ ipv6rs_start(struct interface *ifp)
 {
        struct rs_state *state;
 
-       eloop_timeout_delete(NULL, ifp);
-
-       state = RS_STATE(ifp);
-       if (state == NULL) {
-               ifp->if_data[IF_DATA_IPV6RS] = xzalloc(sizeof(*state));
-               state = RS_STATE(ifp);
+       if (sock == -1) {
+               if (ipv6rs_open() == -1) {
+                       syslog(LOG_ERR, "%s: ipv6rs_open: %m", __func__);
+                       return -1;
+               }
+               eloop_event_add(sock, ipv6rs_handledata, NULL);
        }
 
-       /* Always make a new probe as the underlying hardware
-        * address could have changed. */
-       ipv6rs_makeprobe(ifp);
-       if (state->rs == NULL)
-               return -1;
+       eloop_timeout_delete(NULL, ifp);
+       state = RS_STATE(ifp);
+       if (state == NULL) {
+               ifp->if_data[IF_DATA_IPV6RS] = calloc(1, sizeof(*state));
+               state = RS_STATE(ifp);
+               if (state == NULL) {
+                       syslog(LOG_ERR, "%s: %m", __func__);
+                       return -1;
+               }
+       }
+       /* Always make a new probe as the underlying hardware
+        * address could have changed. */
+       ipv6rs_makeprobe(ifp);
+       if (state->rs == NULL) {
+               syslog(LOG_ERR, "%s: ipv6rs_makeprobe: %m", __func__);
+               return -1;
+       }
 
        state->rsprobes = 0;
        ipv6rs_sendprobe(ifp);