summaryrefslogtreecommitdiffstats
path: root/ipv6rs.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2013-02-15 20:33:13 +0000
committerRoy Marples <roy@marples.name>2013-02-15 20:33:13 +0000
commitfbbb0875dd748a22dcf6d91a7d3cdaed5a90dc58 (patch)
treec67f12a8c0734c78e69f12614ec7bbe945547204 /ipv6rs.c
parentcebe222c56901ba2f943a07eaf815d9660ba836b (diff)
downloaddhcpcd-fbbb0875dd748a22dcf6d91a7d3cdaed5a90dc58.tar.xz
Instead of opening link, ipv6, ipv6rs and ipv6ns sockets globally,
only open when the first link wanting this features needs it. Hopefully fixes #263 and #264.
Diffstat (limited to 'ipv6rs.c')
-rw-r--r--ipv6rs.c75
1 files changed, 50 insertions, 25 deletions
diff --git a/ipv6rs.c b/ipv6rs.c
index 8193fa00..ac30346c 100644
--- 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);