]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Move all global variables into contexts, with a small exception for
authorRoy Marples <roy@marples.name>
Wed, 12 Feb 2014 00:39:46 +0000 (00:39 +0000)
committerRoy Marples <roy@marples.name>
Wed, 12 Feb 2014 00:39:46 +0000 (00:39 +0000)
signal handling.
This allows dhcpcd to work better in a threaded environment such as rtems.

41 files changed:
arp.c
auth.c
auth.h
common.c
common.h
control.c
control.h
dev.c
dev.h
dev/udev.c
dhcp-common.c
dhcp-common.h
dhcp.c
dhcp.h
dhcp6.c
dhcp6.h
dhcpcd.c
dhcpcd.h
duid.c
duid.h
eloop.c
eloop.h
if-bsd.c
if-linux.c
if-options.c
if-options.h
if-pref.c
if-pref.h
ipv4.c
ipv4.h
ipv4ll.c
ipv6.c
ipv6.h
ipv6nd.c
ipv6nd.h
net.c
net.h
platform-bsd.c
platform-linux.c
platform.h
script.c

diff --git a/arp.c b/arp.c
index a2310180b6185bb7dbbab17ef0a93ce966f604f1..d6c5aeb041e03096f52881e231a3bf9a28b1f0fb 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -106,11 +106,12 @@ arp_failure(struct interface *ifp)
        unlink(state->leasefile);
        if (!state->lease.frominfo)
                dhcp_decline(ifp);
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        if (state->lease.frominfo)
                start_interface(ifp);
        else
-               eloop_timeout_add_sec(DHCP_ARP_FAIL, start_interface, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   DHCP_ARP_FAIL, start_interface, ifp);
 }
 
 static void
@@ -127,6 +128,7 @@ arp_packet(void *arg)
        struct if_options *opts = ifp->options;
        const char *hwaddr;
        struct in_addr ina;
+       char hwbuf[HWADDR_LEN * 3];
 
        state = D_STATE(ifp);
        state->fail.s_addr = 0;
@@ -172,7 +174,7 @@ arp_packet(void *arg)
                {
                        ina.s_addr = reply_s;
                        hwaddr = hwaddr_ntoa((unsigned char *)hw_s,
-                           (size_t)ar.ar_hln);
+                           (size_t)ar.ar_hln, hwbuf, sizeof(hwbuf));
                        syslog(LOG_INFO,
                            "%s: found %s on hardware address %s",
                            ifp->name, inet_ntoa(ina), hwaddr);
@@ -180,7 +182,7 @@ arp_packet(void *arg)
                            errno == ENOENT)
                                select_profile(ifp, inet_ntoa(ina));
                        dhcp_close(ifp);
-                       eloop_timeout_delete(NULL, ifp);
+                       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
                        start_interface(ifp);
                        return;
                }
@@ -201,7 +203,7 @@ arp_packet(void *arg)
                        syslog(LOG_ERR, "%s: hardware address %s claims %s",
                            ifp->name,
                            hwaddr_ntoa((unsigned char *)hw_s,
-                               (size_t)ar.ar_hln),
+                               (size_t)ar.ar_hln, hwbuf, sizeof(hwbuf)),
                            inet_ntoa(state->fail));
                        errno = EEXIST;
                        arp_failure(ifp);
@@ -225,7 +227,8 @@ arp_announce(void *arg)
                        syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name);
                        return;
                }
-               eloop_event_add(state->arp_fd, arp_packet, ifp);
+               eloop_event_add(ifp->ctx->eloop,
+                   state->arp_fd, arp_packet, ifp);
        }
        if (++state->claims < ANNOUNCE_NUM)
                syslog(LOG_DEBUG,
@@ -240,7 +243,8 @@ arp_announce(void *arg)
                state->new->yiaddr, state->new->yiaddr) == -1)
                syslog(LOG_ERR, "send_arp: %m");
        if (state->claims < ANNOUNCE_NUM) {
-               eloop_timeout_add_sec(ANNOUNCE_WAIT, arp_announce, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   ANNOUNCE_WAIT, arp_announce, ifp);
                return;
        }
        if (state->new->cookie != htonl(MAGIC_COOKIE)) {
@@ -256,9 +260,9 @@ arp_announce(void *arg)
                tv.tv_sec = state->interval - DHCP_RAND_MIN;
                tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U);
                timernorm(&tv);
-               eloop_timeout_add_tv(&tv, dhcp_discover, ifp);
+               eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_discover, ifp);
        } else {
-               eloop_event_delete(state->arp_fd);
+               eloop_event_delete(ifp->ctx->eloop, state->arp_fd);
                close(state->arp_fd);
                state->arp_fd = -1;
        }
@@ -279,7 +283,8 @@ arp_probe(void *arg)
                        syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name);
                        return;
                }
-               eloop_event_add(state->arp_fd, arp_packet, ifp);
+               eloop_event_add(ifp->ctx->eloop,
+                   state->arp_fd, arp_packet, ifp);
        }
 
        if (state->arping_index < ifp->options->arping_len) {
@@ -305,18 +310,21 @@ arp_probe(void *arg)
                tv.tv_sec = PROBE_MIN;
                tv.tv_usec = arc4random() % (PROBE_MAX_U - PROBE_MIN_U);
                timernorm(&tv);
-               eloop_timeout_add_tv(&tv, arp_probe, ifp);
+               eloop_timeout_add_tv(ifp->ctx->eloop, &tv, arp_probe, ifp);
        } else {
                tv.tv_sec = ANNOUNCE_WAIT;
                tv.tv_usec = 0;
                if (arping) {
                        state->probes = 0;
                        if (++state->arping_index < ifp->options->arping_len)
-                               eloop_timeout_add_tv(&tv, arp_probe, ifp);
+                               eloop_timeout_add_tv(ifp->ctx->eloop,
+                                   &tv, arp_probe, ifp);
                        else
-                               eloop_timeout_add_tv(&tv, start_interface, ifp);
+                               eloop_timeout_add_tv(ifp->ctx->eloop,
+                                   &tv, start_interface, ifp);
                } else
-                       eloop_timeout_add_tv(&tv, dhcp_bind, ifp);
+                       eloop_timeout_add_tv(ifp->ctx->eloop,
+                           &tv, dhcp_bind, ifp);
        }
        syslog(LOG_DEBUG,
            "%s: sending ARP probe (%d of %d), next in %0.1f seconds",
@@ -345,7 +353,7 @@ arp_close(struct interface *ifp)
                return;
 
        if (state->arp_fd != -1) {
-               eloop_event_delete(state->arp_fd);
+               eloop_event_delete(ifp->ctx->eloop, state->arp_fd);
                close(state->arp_fd);
                state->arp_fd = -1;
        }
diff --git a/auth.c b/auth.c
index f7d546e1ffa72722ac3937eed4e4c83c8ceaf29f..553148bc6b06ad18a678093f6af8028c6e4a3a7c 100644 (file)
--- a/auth.c
+++ b/auth.c
@@ -368,10 +368,8 @@ finish:
        return t;
 }
 
-static uint64_t last_rdm;
-static uint8_t last_rdm_set;
 static uint64_t
-get_next_rdm_monotonic_counter(void)
+get_next_rdm_monotonic_counter(struct auth *auth)
 {
        FILE *fp;
        uint64_t rdm;
@@ -380,10 +378,10 @@ get_next_rdm_monotonic_counter(void)
        fp = fopen(RDM_MONOFILE, "r+");
        if (fp == NULL) {
                if (errno != ENOENT)
-                       return ++last_rdm; /* report error? */
+                       return ++auth->last_replay; /* report error? */
                fp = fopen(RDM_MONOFILE, "w");
                if (fp == NULL)
-                       return ++last_rdm; /* report error? */
+                       return ++auth->last_replay; /* report error? */
                flocked = flock(fileno(fp), LOCK_EX);
                rdm = 0;
        } else {
@@ -397,11 +395,11 @@ get_next_rdm_monotonic_counter(void)
            ftruncate(fileno(fp), 0) == -1 ||
            fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19)
        {
-               if (!last_rdm_set) {
-                       last_rdm = rdm;
-                       last_rdm_set = 1;
+               if (!auth->last_replay_set) {
+                       auth->last_replay = rdm;
+                       auth->last_replay_set = 1;
                } else
-                       rdm = ++last_rdm;
+                       rdm = ++auth->last_replay;
                /* report error? */
        }
        fflush(fp);
@@ -413,7 +411,7 @@ get_next_rdm_monotonic_counter(void)
 
 #define JAN_1970       2208988800UL    /* 1970 - 1900 in seconds */
 static uint64_t
-get_next_rdm_monotonic_clock(void)
+get_next_rdm_monotonic_clock(struct auth *auth)
 {
        struct timespec ts;
        uint32_t pack[2];
@@ -421,7 +419,7 @@ get_next_rdm_monotonic_clock(void)
        uint64_t rdm;
 
        if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
-               return ++last_rdm; /* report error? */
+               return ++auth->last_replay; /* report error? */
        pack[0] = htonl((uint32_t)ts.tv_sec + JAN_1970);
        frac = (ts.tv_nsec / 1e9 * 0x100000000ULL);
        pack[1] = htonl((uint32_t)frac);
@@ -431,12 +429,12 @@ get_next_rdm_monotonic_clock(void)
 }
 
 static uint64_t
-get_next_rdm_monotonic(const struct auth *auth)
+get_next_rdm_monotonic(struct auth *auth)
 {
 
        if (auth->options & DHCPCD_AUTH_RDM_COUNTER)
-               return get_next_rdm_monotonic_counter();
-       return get_next_rdm_monotonic_clock();
+               return get_next_rdm_monotonic_counter(auth);
+       return get_next_rdm_monotonic_clock(auth);
 }
 
 /*
@@ -450,7 +448,7 @@ get_next_rdm_monotonic(const struct auth *auth)
  * data and dlen refer to the authentication option within the message.
  */
 int
-dhcp_auth_encode(const struct auth *auth, const struct token *t,
+dhcp_auth_encode(struct auth *auth, const struct token *t,
     uint8_t *m, unsigned int mlen, int mp, int mt,
     uint8_t *data, unsigned int dlen)
 {
diff --git a/auth.h b/auth.h
index 7a26fc02b381061e533395a282f1a05c1a0519f4..1ad7e9c8d14e825bb8ee19feec871a648679e649 100644 (file)
--- a/auth.h
+++ b/auth.h
@@ -62,6 +62,8 @@ struct auth {
        uint8_t protocol;
        uint8_t algorithm;
        uint8_t rdm;
+       uint64_t last_replay;
+       uint8_t last_replay_set;
        struct token_head tokens;
 };
 
@@ -78,7 +80,7 @@ const struct token * dhcp_auth_validate(struct authstate *,
     const uint8_t *, unsigned int, int, int,
     const uint8_t *, unsigned int);
 
-int dhcp_auth_encode(const struct auth *, const struct token *,
+int dhcp_auth_encode(struct auth *, const struct token *,
     uint8_t *, unsigned int, int, int,
     uint8_t *, unsigned int);
 #endif
index e4e294cae64e78dcfa0e0b88df80e4c140ea44cc..95d1e70f8992cf2e7279ca6b1994afa797057764 100644 (file)
--- a/common.c
+++ b/common.c
 #  define _PATH_DEVNULL "/dev/null"
 #endif
 
-static char hostname_buffer[HOSTNAME_MAX_LEN + 1];
-int clock_monotonic;
-
 const char *
-get_hostname(int short_hostname)
+get_hostname(char *buf, size_t buflen, int short_hostname)
 {
        char *p;
 
-       gethostname(hostname_buffer, sizeof(hostname_buffer));
-       hostname_buffer[sizeof(hostname_buffer) - 1] = '\0';
-       if (strcmp(hostname_buffer, "(none)") == 0 ||
-           strcmp(hostname_buffer, "localhost") == 0 ||
-           strncmp(hostname_buffer, "localhost.", strlen("localhost.")) == 0 ||
-           hostname_buffer[0] == '.')
+       if (gethostname(buf, buflen) != 0)
+               return NULL;
+       buf[buflen - 1] = '\0';
+       if (strcmp(buf, "(none)") == 0 ||
+           strcmp(buf, "localhost") == 0 ||
+           strncmp(buf, "localhost.", strlen("localhost.")) == 0 ||
+           buf[0] == '.')
                return NULL;
 
        if (short_hostname) {
-               p = strchr(hostname_buffer, '.');
+               p = strchr(buf, '.');
                if (p)
                        *p = '\0';
        }
 
-       return hostname_buffer;
+       return buf;
 }
 
 /* Handy function to get the time.
@@ -94,24 +92,13 @@ get_hostname(int short_hostname)
 int
 get_monotonic(struct timeval *tp)
 {
-       static int posix_clock_set = 0;
 #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
        struct timespec ts;
-       static clockid_t posix_clock;
 
-       if (!posix_clock_set) {
-               if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
-                       posix_clock = CLOCK_MONOTONIC;
-                       clock_monotonic = posix_clock_set = 1;
-               }
-       }
-
-       if (clock_monotonic) {
-               if (clock_gettime(posix_clock, &ts) == 0) {
-                       tp->tv_sec = ts.tv_sec;
-                       tp->tv_usec = ts.tv_nsec / 1000;
-                       return 0;
-               }
+       if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+               tp->tv_sec = ts.tv_sec;
+               tp->tv_usec = ts.tv_nsec / 1000;
+               return 0;
        }
 #elif defined(__APPLE__)
 #define NSEC_PER_SEC 1000000000
@@ -143,11 +130,13 @@ get_monotonic(struct timeval *tp)
        }
 #endif
 
+#if 0
        /* Something above failed, so fall back to gettimeofday */
        if (!posix_clock_set) {
                syslog(LOG_WARNING, NO_MONOTONIC);
                posix_clock_set = 1;
        }
+#endif
        return gettimeofday(tp, NULL);
 }
 
index c8a77b47d9769bf786dc1069251b978a239aa244..43c028031eba2bab0ba6665c1817f4b72971d45a 100644 (file)
--- a/common.h
+++ b/common.h
 #endif
 
 void get_line_free(void);
-const char *get_hostname(int);
+const char *get_hostname(char *, size_t, int);
 extern int clock_monotonic;
 int get_monotonic(struct timeval *);
 ssize_t setvar(char ***, const char *, const char *, const char *);
index 645e54fb9007329ef38a14eb9d67dd50126296fc..6688327230d0bcedb9fe61876e5303eb508e0b51 100644 (file)
--- a/control.c
+++ b/control.c
             (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
 #endif
 
-
-struct fd_list *control_fds = NULL;
-
 static void
 control_remove(void *arg)
 {
+       struct dhcpcd_ctx *ctx;
        struct fd_list *l, *n, *last = NULL;
 
-       l = control_fds;
+       ctx = arg;
+       l = ctx->control_fds;
        while (l) {
                n = l->next;
                if (l == arg) {
                        close(l->fd);
-                       eloop_event_delete(l->fd);
+                       eloop_event_delete(ctx->eloop, l->fd);
                        if (last == NULL)
-                               control_fds = l->next;
+                               ctx->control_fds = l->next;
                        else
                                last->next = l->next;
                        free(l);
@@ -96,14 +95,13 @@ control_handle_data(void *arg)
                *ap++ = p;
                p += strlen(p) + 1;
        }
-       handle_args(l, argc, argvp);
+       handle_args(l->ctx, l, argc, argvp);
 }
 
-/* ARGSUSED */
 static void
 control_handle(void *arg)
 {
-       struct control_ctx *ctx;
+       struct dhcpcd_ctx *ctx;
        struct sockaddr_un run;
        socklen_t len;
        struct fd_list *l;
@@ -111,7 +109,7 @@ control_handle(void *arg)
 
        ctx = arg;
        len = sizeof(run);
-       if ((fd = accept(ctx->fd, (struct sockaddr *)&run, &len)) == -1)
+       if ((fd = accept(ctx->control_fd, (struct sockaddr *)&run, &len)) == -1)
                return;
        if ((flags = fcntl(fd, F_GETFD, 0)) == -1 ||
            fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
@@ -121,20 +119,21 @@ control_handle(void *arg)
        }
        l = malloc(sizeof(*l));
        if (l) {
+               l->ctx = ctx;
                l->fd = fd;
                l->listener = 0;
-               l->next = control_fds;
-               control_fds = l;
-               eloop_event_add(l->fd, control_handle_data, l);
+               l->next = ctx->control_fds;
+               ctx->control_fds = l;
+               eloop_event_add(ctx->eloop, l->fd, control_handle_data, l);
        } else
                close(fd);
 }
 
 static int
-make_sock(struct control_ctx *ctx, struct sockaddr_un *sun)
+make_sock(struct dhcpcd_ctx *ctx, struct sockaddr_un *sun)
 {
 
-       if ((ctx->fd = socket(AF_UNIX,
+       if ((ctx->control_fd = socket(AF_UNIX,
            SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1)
                return -1;
        memset(sun, 0, sizeof(*sun));
@@ -144,7 +143,7 @@ make_sock(struct control_ctx *ctx, struct sockaddr_un *sun)
 }
 
 int
-control_start(struct control_ctx *ctx)
+control_start(struct dhcpcd_ctx *ctx)
 {
        struct sockaddr_un sun;
        int len;
@@ -152,57 +151,57 @@ control_start(struct control_ctx *ctx)
        if ((len = make_sock(ctx, &sun)) == -1)
                return -1;
        unlink(CONTROLSOCKET);
-       if (bind(ctx->fd, (struct sockaddr *)&sun, len) == -1 ||
+       if (bind(ctx->control_fd, (struct sockaddr *)&sun, len) == -1 ||
            chmod(CONTROLSOCKET,
                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1 ||
-           listen(ctx->fd, sizeof(control_fds)) == -1)
+           listen(ctx->control_fd, sizeof(ctx->control_fds)) == -1)
        {
-               close(ctx->fd);
-               ctx->fd = -1;
+               close(ctx->control_fd);
+               ctx->control_fd = -1;
                return -1;
        }
-       eloop_event_add(ctx->fd, control_handle, ctx);
-       return ctx->fd;
+       eloop_event_add(ctx->eloop, ctx->control_fd, control_handle, ctx);
+       return ctx->control_fd;
 }
 
 int
-control_stop(struct control_ctx *ctx)
+control_stop(struct dhcpcd_ctx *ctx)
 {
        int retval = 0;
        struct fd_list *l;
 
-       eloop_event_delete(ctx->fd);
-       if (shutdown(ctx->fd, SHUT_RDWR) == -1)
+       eloop_event_delete(ctx->eloop, ctx->control_fd);
+       if (shutdown(ctx->control_fd, SHUT_RDWR) == -1)
                retval = 1;
-       ctx->fd = -1;
+       ctx->control_fd = -1;
        if (unlink(CONTROLSOCKET) == -1)
                retval = -1;
 
-       l = control_fds;
+       l = ctx->control_fds;
        while (l != NULL) {
-               control_fds = l->next;
-               eloop_event_delete(l->fd);
+               ctx->control_fds = l->next;
+               eloop_event_delete(ctx->eloop, l->fd);
                shutdown(l->fd, SHUT_RDWR);
                free(l);
-               l = control_fds;
+               l = ctx->control_fds;
        }
 
        return retval;
 }
 
 int
-control_open(struct control_ctx *ctx)
+control_open(struct dhcpcd_ctx *ctx)
 {
        struct sockaddr_un sun;
        int len;
 
        if ((len = make_sock(ctx, &sun)) == -1)
                return -1;
-       return connect(ctx->fd, (struct sockaddr *)&sun, len);
+       return connect(ctx->control_fd, (struct sockaddr *)&sun, len);
 }
 
 int
-control_send(struct control_ctx *ctx, int argc, char * const *argv)
+control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
 {
        char buffer[1024], *p;
        int i;
@@ -222,5 +221,5 @@ control_send(struct control_ctx *ctx, int argc, char * const *argv)
                memcpy(p, argv[i], len);
                p += len;
        }
-       return write(ctx->fd, buffer, p - buffer);
+       return write(ctx->control_fd, buffer, p - buffer);
 }
index 233c033f96da586991599ed233f2fa3b9def299d..5ca647f7c9ad5f364decf50243fbdd00419efdbf 100644 (file)
--- a/control.h
+++ b/control.h
 #ifndef CONTROL_H
 #define CONTROL_H
 
+#include "dhcpcd.h"
+
 struct fd_list {
-       int fd;
-       int listener;
        struct fd_list *next;
-};
-extern struct fd_list *control_fds;
-
-struct control_ctx {
+       struct dhcpcd_ctx *ctx;
        int fd;
+       int listener;
 };
 
-int control_start(struct control_ctx *);
-int control_stop(struct control_ctx *);
-int control_open(struct control_ctx *);
-int control_send(struct control_ctx *, int, char * const *);
+int control_start(struct dhcpcd_ctx *);
+int control_stop(struct dhcpcd_ctx *);
+int control_open(struct dhcpcd_ctx *);
+int control_send(struct dhcpcd_ctx *, int, char * const *);
 
 #endif
diff --git a/dev.c b/dev.c
index fe5eb18e6c51f4132e51ecd180f34852130870ef..0ace151d58ae152b35cda2f755d1ad31ff7b6412 100644 (file)
--- a/dev.c
+++ b/dev.c
 #include <string.h>
 #include <syslog.h>
 
+#define _INDEV
 #include "common.h"
 #include "dev.h"
 #include "eloop.h"
 #include "dhcpcd.h"
 
-static struct dev *dev;
-static void *handle;
-static int fd = -1;
-
-static struct dev_dhcpcd dev_dhcpcd = {
-       .handle_interface = &handle_interface
-};
-
 int
-dev_initialized(const char *ifname)
+dev_initialized(struct dhcpcd_ctx *ctx, const char *ifname)
 {
 
-       if (dev == NULL)
+       if (ctx->dev == NULL)
                return 1;
-       return dev->initialized(ifname);
+       return ctx->dev->initialized(ifname);
 }
 
 int
-dev_listening(void)
+dev_listening(struct dhcpcd_ctx *ctx)
 {
 
-       if (dev == NULL)
+       if (ctx->dev == NULL)
                return 0;
-       return dev->listening();
+       return ctx->dev->listening();
 }
 
 void
-dev_stop(int stop)
+dev_stop(struct dhcpcd_ctx *ctx, int stop)
 {
 
-       if (dev) {
+       if (ctx->dev) {
                if (stop)
-                       syslog(LOG_DEBUG, "dev: unloaded %s", dev->name);
-               dev->stop();
-               free(dev);
-               dev = NULL;
-               fd = -1;
+                       syslog(LOG_DEBUG, "dev: unloaded %s", ctx->dev->name);
+               ctx->dev->stop();
+               eloop_event_delete(ctx->eloop, ctx->dev_fd);
+               free(ctx->dev);
+               ctx->dev = NULL;
+               ctx->dev_fd = -1;
        }
-       if (handle) {
-               dlclose(handle);
-               handle = NULL;
+       if (ctx->dev_handle) {
+               dlclose(ctx->dev_handle);
+               ctx->dev_handle = NULL;
        }
 }
 
 static int
-dev_start2(const char *name)
+dev_start2(struct dhcpcd_ctx *ctx, const char *name)
 {
        char file[PATH_MAX];
        void *h;
        void (*fptr)(struct dev *, const struct dev_dhcpcd *);
        int r;
+       struct dev_dhcpcd dev_dhcpcd;
 
        snprintf(file, sizeof(file), DEVDIR "/%s", name);
        h = dlopen(file, RTLD_LAZY);
@@ -101,33 +96,34 @@ dev_start2(const char *name)
                dlclose(h);
                return -1;
        }
-       dev = calloc(1, sizeof(*dev));
-       fptr(dev, &dev_dhcpcd);
-       if (dev->start  == NULL || (r = dev->start()) == -1) {
-               free(dev);
-               dev = NULL;
+       ctx->dev = calloc(1, sizeof(*ctx->dev));
+       dev_dhcpcd.handle_interface = &handle_interface;
+       fptr(ctx->dev, &dev_dhcpcd);
+       if (ctx->dev->start  == NULL || (r = ctx->dev->start()) == -1) {
+               free(ctx->dev);
+               ctx->dev = NULL;
                dlclose(h);
                return -1;
        }
-       syslog(LOG_INFO, "dev: loaded %s", dev->name);
-       handle = h;
+       syslog(LOG_INFO, "dev: loaded %s", ctx->dev->name);
+       ctx->dev_handle = h;
        return r;
 }
 
 static int
-dev_start1(const char *plugin)
+dev_start1(struct dhcpcd_ctx *ctx)
 {
        DIR *dp;
        struct dirent *d;
        int r;
 
-       if (dev) {
-               syslog(LOG_ERR, "dev: already started %s", dev->name);
+       if (ctx->dev) {
+               syslog(LOG_ERR, "dev: already started %s", ctx->dev->name);
                return -1;
        }
 
-       if (plugin)
-               return dev_start2(plugin);
+       if (ctx->dev_load)
+               return dev_start2(ctx, ctx->dev_load);
 
        dp = opendir(DEVDIR);
        if (dp == NULL) {
@@ -140,7 +136,7 @@ dev_start1(const char *plugin)
                if (d->d_name[0] == '.')
                        continue;
 
-               r = dev_start2(d->d_name);
+               r = dev_start2(ctx, d->d_name);
                if (r != -1)
                        break;
        }
@@ -149,31 +145,36 @@ dev_start1(const char *plugin)
 }
 
 static void
-dev_handle_data(__unused void *arg)
+dev_handle_data(void *arg)
 {
+       struct dhcpcd_ctx *ctx;
 
-       if (dev->handle_device() == -1) {
+       ctx = arg;
+       if (ctx->dev->handle_device(arg) == -1) {
                /* XXX: an error occured. should we restart dev? */
        }
 }
 
 int
-dev_start(const char *plugin)
+dev_start(struct dhcpcd_ctx *ctx)
 {
 
-       if (fd != -1) {
-               syslog(LOG_ERR, "%s: already started on fd %d", __func__, fd);
-               return fd;
+       if (ctx->dev_fd != -1) {
+               syslog(LOG_ERR, "%s: already started on fd %d", __func__,
+                   ctx->dev_fd);
+               return ctx->dev_fd;
        }
 
-       fd = dev_start1(plugin);
-       if (fd != -1) {
-               if (eloop_event_add(fd, dev_handle_data, NULL) == -1) {
+       ctx->dev_fd = dev_start1(ctx);
+       if (ctx->dev_fd != -1) {
+               if (eloop_event_add(ctx->eloop,
+                       ctx->dev_fd, dev_handle_data, ctx) == -1)
+               {
                        syslog(LOG_ERR, "%s: eloop_event_add: %m", __func__);
-                       dev_stop(1);
+                       dev_stop(ctx, 1);
                        return -1;
                }
        }
 
-       return fd;
+       return ctx->dev_fd;
 }
diff --git a/dev.h b/dev.h
index 16a287412908a1154288ef887d83698ee8064d74..55cb290c18e4c802e65c84fef79d6d50062c28d6 100644 (file)
--- a/dev.h
+++ b/dev.h
@@ -32,28 +32,29 @@ struct dev {
        const char *name;
        int (*initialized)(const char *);
        int (*listening)(void);
-       int (*handle_device)(void);
+       int (*handle_device)(void *);
        int (*start)(void);
        void (*stop)(void);
 };
 
 struct dev_dhcpcd {
-       void (*handle_interface)(int, const char *);
+       void (*handle_interface)(void *, int, const char *);
 };
 
 int dev_init(struct dev *, const struct dev_dhcpcd *);
 
 // hooks for dhcpcd
 #ifdef PLUGIN_DEV
-int dev_initialized(const char *);
-int dev_listening(void);
-int dev_start(const char *);
-void dev_stop(int);
+#include "dhcpcd.h"
+int dev_initialized(struct dhcpcd_ctx *, const char *);
+int dev_listening(struct dhcpcd_ctx *);
+int dev_start(struct dhcpcd_ctx *);
+void dev_stop(struct dhcpcd_ctx *, int);
 #else
-#define dev_initialized(a) 1
-#define dev_listening() 0
+#define dev_initialized(a, b) 1
+#define dev_listening(a) 0
 #define dev_start(a) {}
-#define dev_stop(a) {}
+#define dev_stop(a, b) {}
 #endif
 
 #endif
index 0b02ffb809f2bf083699bab7f0e1c4e7e441f927..57c27cd6c22c29d7dae61bf6d3e1d2d804e11f30 100644 (file)
@@ -73,7 +73,7 @@ udev_initialized(const char *ifname)
 }
 
 static int
-udev_handle_device(void)
+udev_handle_device(void *ctx)
 {
        struct udev_device *device;
        const char *subsystem, *ifname, *action;
@@ -92,9 +92,9 @@ udev_handle_device(void)
        if (strcmp(subsystem, "net") == 0) {
                syslog(LOG_DEBUG, "%s: libudev: %s", ifname, action);
                if (strcmp(action, "add") == 0 || strcmp(action, "move") == 0)
-                       dhcpcd->handle_interface(1, ifname);
+                       dhcpcd->handle_interface(ctx, 1, ifname);
                else if (strcmp(action, "remove") == 0)
-                       dhcpcd->handle_interface(-1, ifname);
+                       dhcpcd->handle_interface(ctx, -1, ifname);
        }
 
        udev_device_unref(device);
index 7379be2ebf497cb7f99a71a9cf93ceb26bbe9965..dfda0254979565faad4796b368bbdec4a07fb6ca 100644 (file)
 #include "dhcp.h"
 #include "platform.h"
 
-/* DHCP Enterprise options, RFC3925 */
-struct dhcp_opt *vivso = NULL;
-size_t vivso_len = 0;
-
 struct dhcp_opt *
 vivso_find(uint16_t iana_en, const void *arg)
 {
@@ -60,7 +56,7 @@ vivso_find(uint16_t iana_en, const void *arg)
                        if (opt->option == iana_en)
                                return opt;
        }
-       for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
+       for (i = 0, opt = ifp->ctx->vivso; i < ifp->ctx->vivso_len; i++, opt++)
                if (opt->option == iana_en)
                        return opt;
        return NULL;
@@ -576,9 +572,10 @@ dhcp_envoption1(char **env, const char *prefix,
 }
 
 ssize_t
-dhcp_envoption(char **env, const char *prefix,
+dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
     const char *ifname, struct dhcp_opt *opt,
-    const uint8_t *(*dgetopt)(unsigned int *, unsigned int *, unsigned int *,
+    const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
+    unsigned int *, unsigned int *, unsigned int *,
     const uint8_t *, unsigned int, struct dhcp_opt **),
     const uint8_t *od, int ol)
 {
@@ -652,13 +649,13 @@ dhcp_envoption(char **env, const char *prefix,
                {
                        eoc = opt->option;
                        if (eopt->type & OPTION) {
-                               dgetopt(NULL, &eoc, NULL, NULL, 0, &oopt);
+                               dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
                                if (oopt)
                                        oopt->index = 0;
                        }
                }
 
-               while ((eod = dgetopt(&eos, &eoc, &eol, od, ol, &oopt))) {
+               while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
                        for (i = 0, eopt = opt->encopts;
                            i < opt->encopts_len;
                            i++, eopt++)
@@ -669,7 +666,7 @@ dhcp_envoption(char **env, const char *prefix,
                                                        /* Report error? */
                                                        continue;
                                        }
-                                       n += dhcp_envoption(
+                                       n += dhcp_envoption(ctx,
                                            env == NULL ? NULL : &env[n], pfx,
                                            ifname,
                                            eopt->type & OPTION ? oopt : eopt,
index df3083dee080e374fae1101f0e93303d360583bb..6fa19da92fdbc697183b61ec3e1fdb8412100fe9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 #include <stdint.h>
 
 #include "common.h"
+#include "dhcpcd.h"
 
 /* Max MTU - defines dhcp option length */
 #define MTU_MAX             1500
@@ -79,10 +80,6 @@ struct dhcp_opt {
        size_t encopts_len;
 };
 
-/* DHCP Vendor-Identifying Vendor Options, RFC3925 */
-extern struct dhcp_opt *vivso;
-extern size_t vivso_len;
-
 struct dhcp_opt *vivso_find(uint16_t, const void *);
 
 size_t dhcp_vendor(char *, size_t);
@@ -98,8 +95,10 @@ ssize_t decode_rfc3397(char *, ssize_t, int, const uint8_t *);
 ssize_t print_string(char *, ssize_t, int, const uint8_t *);
 ssize_t print_option(char *, ssize_t, int, int, const uint8_t *, const char *);
 
-ssize_t dhcp_envoption(char **, const char *, const char *, struct dhcp_opt *,
-    const uint8_t *(*dgetopt)(unsigned int *, unsigned int *, unsigned int *,
+ssize_t dhcp_envoption(struct dhcpcd_ctx *,
+    char **, const char *, const char *, struct dhcp_opt *,
+    const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
+    unsigned int *, unsigned int *, unsigned int *,
     const uint8_t *, unsigned int, struct dhcp_opt **),
     const uint8_t *od, int ol);
 void dhcp_zero_index(struct dhcp_opt *);
diff --git a/dhcp.c b/dhcp.c
index 4db37e37070e4d48c08865e6b1e633095a9ffb32..5ada15650ee830f2fdd010fb8d0404698c63849b 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
 #define DAD            "Duplicate address detected"
 #define DHCP_MIN_LEASE 20
 
-static uint8_t *packet;
-
-/* Our aggregate option buffer.
- * We ONLY use this when options are split, which for most purposes is
- * practically never. See RFC3396 for details. */
-static uint8_t *opt_buffer;
-
 #define IPV4A          ADDRIPV4 | ARRAY
 #define IPV4R          ADDRIPV4 | REQUEST
 
@@ -121,16 +114,12 @@ struct udp_dhcp_packet
        struct dhcp_message dhcp;
 };
 
-struct dhcp_opt *dhcp_opts = NULL;
-size_t dhcp_opts_len = 0;
-
-static int udp_fd = -1;
 static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
 
 static int dhcp_open(struct interface *);
 
 void
-dhcp_printoptions(void)
+dhcp_printoptions(const struct dhcpcd_ctx *ctx)
 {
        const char * const *p;
        size_t i;
@@ -139,13 +128,14 @@ dhcp_printoptions(void)
        for (p = dhcp_params; *p; p++)
                printf("    %s\n", *p);
 
-       for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++)
+       for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++)
                printf("%03d %s\n", opt->option, opt->var);
 }
 
-#define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL)
+#define get_option_raw(ctx, dhcp, opt) get_option(ctx, dhcp, opt, NULL)
 static const uint8_t *
-get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len)
+get_option(struct dhcpcd_ctx *ctx,
+    const struct dhcp_message *dhcp, uint8_t opt, int *len)
 {
        const uint8_t *p = dhcp->options;
        const uint8_t *e = p + sizeof(dhcp->options);
@@ -160,13 +150,13 @@ get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len)
                o = *p++;
                if (o == opt) {
                        if (op) {
-                               if (!opt_buffer) {
-                                       opt_buffer = malloc(sizeof(*dhcp));
-                                       if (opt_buffer == NULL)
+                               if (!ctx->opt_buffer) {
+                                       ctx->opt_buffer = malloc(sizeof(*dhcp));
+                                       if (ctx->opt_buffer == NULL)
                                                return NULL;
                                }
                                if (!bp)
-                                       bp = opt_buffer;
+                                       bp = ctx->opt_buffer;
                                memcpy(bp, op, ol);
                                bp += ol;
                        }
@@ -210,7 +200,7 @@ exit:
                *len = bl;
        if (bp) {
                memcpy(bp, op, ol);
-               return (const uint8_t *)opt_buffer;
+               return (const uint8_t *)ctx->opt_buffer;
        }
        if (op)
                return op;
@@ -219,13 +209,14 @@ exit:
 }
 
 int
-get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp,
+get_option_addr(struct dhcpcd_ctx *ctx,
+    struct in_addr *a, const struct dhcp_message *dhcp,
     uint8_t option)
 {
        const uint8_t *p;
        int len;
 
-       p = get_option(dhcp, option, &len);
+       p = get_option(ctx, dhcp, option, &len);
        if (!p || len < (ssize_t)sizeof(a->s_addr))
                return -1;
        memcpy(&a->s_addr, p, sizeof(a->s_addr));
@@ -233,13 +224,14 @@ get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp,
 }
 
 static int
-get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
+get_option_uint32(struct dhcpcd_ctx *ctx,
+    uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
 {
        const uint8_t *p;
        int len;
        uint32_t d;
 
-       p = get_option(dhcp, option, &len);
+       p = get_option(ctx, dhcp, option, &len);
        if (!p || len < (ssize_t)sizeof(d))
                return -1;
        memcpy(&d, p, sizeof(d));
@@ -249,12 +241,13 @@ get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
 }
 
 static int
-get_option_uint8(uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
+get_option_uint8(struct dhcpcd_ctx *ctx,
+    uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
 {
        const uint8_t *p;
        int len;
 
-       p = get_option(dhcp, option, &len);
+       p = get_option(ctx, dhcp, option, &len);
        if (!p || len < (ssize_t)sizeof(*p))
                return -1;
        if (i)
@@ -489,14 +482,15 @@ decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p)
        return bytes;
 }
 
-char *
-get_option_string(const struct dhcp_message *dhcp, uint8_t option)
+static char *
+get_option_string(struct dhcpcd_ctx *ctx,
+    const struct dhcp_message *dhcp, uint8_t option)
 {
        int len;
        const uint8_t *p;
        char *s;
 
-       p = get_option(dhcp, option, &len);
+       p = get_option(ctx, dhcp, option, &len);
        if (!p || len == 0 || *p == '\0')
                return NULL;
 
@@ -553,12 +547,12 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
 
        /* If we have CSR's then we MUST use these only */
        if (!has_option_mask(ifo->nomask, DHO_CSR))
-               p = get_option(dhcp, DHO_CSR, &len);
+               p = get_option(ifp->ctx, dhcp, DHO_CSR, &len);
        else
                p = NULL;
        /* Check for crappy MS option */
        if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) {
-               p = get_option(dhcp, DHO_MSCSR, &len);
+               p = get_option(ifp->ctx, dhcp, DHO_MSCSR, &len);
                if (p)
                        csr = "MS ";
        }
@@ -583,7 +577,7 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
        }
        TAILQ_INIT(routes);
        if (!has_option_mask(ifo->nomask, DHO_STATICROUTE))
-               p = get_option(dhcp, DHO_STATICROUTE, &len);
+               p = get_option(ifp->ctx, dhcp, DHO_STATICROUTE, &len);
        else
                p = NULL;
        if (p) {
@@ -606,7 +600,7 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
 
        /* Now grab our routers */
        if (!has_option_mask(ifo->nomask, DHO_ROUTER))
-               p = get_option(dhcp, DHO_ROUTER, &len);
+               p = get_option(ifp->ctx, dhcp, DHO_ROUTER, &len);
        else
                p = NULL;
        if (p) {
@@ -672,10 +666,11 @@ make_message(struct dhcp_message **message,
        size_t len, i;
        int auth_len;
        const struct dhcp_opt *opt;
-       const struct if_options *ifo = iface->options;
+       struct if_options *ifo = iface->options;
        const struct dhcp_state *state = D_CSTATE(iface);
        const struct dhcp_lease *lease = &state->lease;
        time_t up = uptime() - state->start_uptime;
+       char hbuf[HOSTNAME_MAX_LEN + 1];
        const char *hostname;
        const struct vivco *vivco;
 
@@ -757,7 +752,7 @@ make_message(struct dhcp_message **message,
        }
 
        if (type == DHCP_DISCOVER &&
-           !(options & DHCPCD_TEST) &&
+           !(iface->ctx->options & DHCPCD_TEST) &&
            has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT))
        {
                /* RFC 4039 Section 3 */
@@ -820,8 +815,8 @@ make_message(struct dhcp_message **message,
                }
 
                if (ifo->hostname[0] == '\0')
-                       hostname = get_hostname(ifo->options &
-                           DHCPCD_HOSTNAME_SHORT ? 1 : 0);
+                       hostname = get_hostname(hbuf, sizeof(hbuf),
+                           ifo->options & DHCPCD_HOSTNAME_SHORT ? 1 : 0);
                else
                        hostname = ifo->hostname;
                if (ifo->fqdn != FQDN_DISABLE) {
@@ -908,7 +903,10 @@ make_message(struct dhcp_message **message,
                *p++ = DHO_PARAMETERREQUESTLIST;
                n_params = p;
                *p++ = 0;
-               for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++) {
+               for (i = 0, opt = iface->ctx->dhcp_opts;
+                   i < iface->ctx->dhcp_opts_len;
+                   i++, opt++)
+               {
                        if (!(opt->type & REQUEST ||
                                has_option_mask(ifo->requestmask, opt->option)))
                                continue;
@@ -982,7 +980,7 @@ write_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
        const struct dhcp_state *state = D_CSTATE(ifp);
 
        /* We don't write BOOTP leases */
-       if (is_bootp(dhcp)) {
+       if (is_bootp(ifp, dhcp)) {
                unlink(state->leasefile);
                return 0;
        }
@@ -1045,10 +1043,10 @@ read_lease(struct interface *ifp)
        }
 
        /* We may have found a BOOTP server */
-       if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1)
+       if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
                type = 0;
        /* Authenticate the message */
-       auth = get_option(dhcp, DHO_AUTHENTICATION, &auth_len);
+       auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
        if (auth) {
                if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
                    (uint8_t *)dhcp, sizeof(*dhcp), 4, type,
@@ -1083,7 +1081,8 @@ dhcp_getoverride(const struct if_options *ifo, uint16_t o)
 }
 
 static const uint8_t *
-dhcp_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
+dhcp_getoption(struct dhcpcd_ctx *ctx,
+    unsigned int *os, unsigned int *code, unsigned int *len,
     const uint8_t *od, unsigned int ol, struct dhcp_opt **oopt)
 {
        size_t i;
@@ -1103,7 +1102,7 @@ dhcp_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
                }
        }
 
-       for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++) {
+       for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
                if (opt->option == *code) {
                        *oopt = opt;
                        break;
@@ -1132,7 +1131,7 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
        uint32_t en;
 
        ifo = ifp->options;
-       get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED);
+       get_option_uint8(ifp->ctx, &overl, dhcp, DHO_OPTIONSOVERLOADED);
 
        if (!env) {
                if (dhcp->yiaddr || dhcp->ciaddr)
@@ -1141,18 +1140,18 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                        e++;
                if (*dhcp->servername && !(overl & 2))
                        e++;
-               for (i = 0, opt = dhcp_opts;
-                   i < dhcp_opts_len;
+               for (i = 0, opt = ifp->ctx->dhcp_opts;
+                   i < ifp->ctx->dhcp_opts_len;
                    i++, opt++)
                {
                        if (has_option_mask(ifo->nomask, opt->option))
                                continue;
                        if (dhcp_getoverride(ifo, opt->option))
                                continue;
-                       p = get_option(dhcp, opt->option, &pl);
+                       p = get_option(ifp->ctx, dhcp, opt->option, &pl);
                        if (!p)
                                continue;
-                       e += dhcp_envoption(NULL, NULL, ifp->name,
+                       e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
                            opt, dhcp_getoption, p, pl);
                }
                for (i = 0, opt = ifo->dhcp_override;
@@ -1161,10 +1160,10 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                {
                        if (has_option_mask(ifo->nomask, opt->option))
                                continue;
-                       p = get_option(dhcp, opt->option, &pl);
+                       p = get_option(ifp->ctx, dhcp, opt->option, &pl);
                        if (!p)
                                continue;
-                       e += dhcp_envoption(NULL, NULL, ifp->name,
+                       e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
                            opt, dhcp_getoption, p, pl);
                }
                return e;
@@ -1176,13 +1175,15 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                 * message but are not necessarily in the options */
                addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
                setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
-               if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
+               if (get_option_addr(ifp->ctx, &net,
+                   dhcp, DHO_SUBNETMASK) == -1) {
                        net.s_addr = ipv4_getnetmask(addr.s_addr);
                        setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
                }
                snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
                setvar(&ep, prefix, "subnet_cidr", cidr);
-               if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1) {
+               if (get_option_addr(ifp->ctx, &brd,
+                   dhcp, DHO_BROADCAST) == -1) {
                        brd.s_addr = addr.s_addr | ~net.s_addr;
                        setvar(&ep, prefix, "broadcast_address",
                            inet_ntoa(brd));
@@ -1199,26 +1200,30 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
 
        /* Zero our indexes */
        if (env) {
-               for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++)
+               for (i = 0, opt = ifp->ctx->dhcp_opts;
+                   i < ifp->ctx->dhcp_opts_len;
+                   i++, opt++)
                        dhcp_zero_index(opt);
                for (i = 0, opt = ifp->options->dhcp_override;
                    i < ifp->options->dhcp_override_len;
                    i++, opt++)
                        dhcp_zero_index(opt);
-               for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
+               for (i = 0, opt = ifp->ctx->vivso;
+                   i < ifp->ctx->vivso_len;
+                   i++, opt++)
                        dhcp_zero_index(opt);
        }
 
-       for (i = 0, opt = dhcp_opts;
-           i < dhcp_opts_len;
+       for (i = 0, opt = ifp->ctx->dhcp_opts;
+           i < ifp->ctx->dhcp_opts_len;
            i++, opt++)
        {
                if (has_option_mask(ifo->nomask, opt->option))
                        continue;
                if (dhcp_getoverride(ifo, opt->option))
                        continue;
-               if ((p = get_option(dhcp, opt->option, &pl))) {
-                       ep += dhcp_envoption(ep, prefix, ifp->name,
+               if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl))) {
+                       ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
                            opt, dhcp_getoption, p, pl);
                        if (opt->option == DHO_VIVSO &&
                            pl > (int)sizeof(uint32_t))
@@ -1230,8 +1235,8 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
                                        /* Skip over en + total size */
                                        p += sizeof(en) + 1;
                                        pl -= sizeof(en) + 1;
-                                       ep += dhcp_envoption(ep, prefix,
-                                           ifp->name,
+                                       ep += dhcp_envoption(ifp->ctx,
+                                           ep, prefix, ifp->name,
                                            vo, dhcp_getoption, p, pl);
                                }
                        }
@@ -1244,16 +1249,17 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
        {
                if (has_option_mask(ifo->nomask, opt->option))
                        continue;
-               if ((p = get_option(dhcp, opt->option, &pl)))
-                       ep += dhcp_envoption(ep, prefix, ifp->name,
+               if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl)))
+                       ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
                            opt, dhcp_getoption, p, pl);
        }
 
        return ep - env;
 }
 
-void
-get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
+static void
+get_lease(struct dhcpcd_ctx *ctx,
+    struct dhcp_lease *lease, const struct dhcp_message *dhcp)
 {
 
        lease->cookie = dhcp->cookie;
@@ -1262,17 +1268,19 @@ get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
                lease->addr.s_addr = dhcp->yiaddr;
        else
                lease->addr.s_addr = dhcp->ciaddr;
-       if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
+       if (get_option_addr(ctx, &lease->net, dhcp, DHO_SUBNETMASK) == -1)
                lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr);
-       if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1)
+       if (get_option_addr(ctx, &lease->brd, dhcp, DHO_BROADCAST) == -1)
                lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
-       if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) != 0)
+       if (get_option_uint32(ctx, &lease->leasetime, dhcp, DHO_LEASETIME) != 0)
                lease->leasetime = ~0U; /* Default to infinite lease */
-       if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
+       if (get_option_uint32(ctx, &lease->renewaltime,
+           dhcp, DHO_RENEWALTIME) != 0)
                lease->renewaltime = 0;
-       if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
+       if (get_option_uint32(ctx, &lease->rebindtime,
+           dhcp, DHO_REBINDTIME) != 0)
                lease->rebindtime = 0;
-       if (get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
+       if (get_option_addr(ctx, &lease->server, dhcp, DHO_SERVERID) != 0)
                lease->server.s_addr = INADDR_ANY;
 }
 
@@ -1322,12 +1330,12 @@ dhcp_close(struct interface *ifp)
                return;
 
        if (state->arp_fd != -1) {
-               eloop_event_delete(state->arp_fd);
+               eloop_event_delete(ifp->ctx->eloop, state->arp_fd);
                close(state->arp_fd);
                state->arp_fd = -1;
        }
        if (state->raw_fd != -1) {
-               eloop_event_delete(state->raw_fd);
+               eloop_event_delete(ifp->ctx->eloop, state->raw_fd);
                close(state->raw_fd);
                state->raw_fd = -1;
        }
@@ -1341,7 +1349,7 @@ dhcp_close(struct interface *ifp)
 }
 
 static int
-dhcp_openudp(struct interface *ifp)
+dhcp_openudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
 {
        int s;
        struct sockaddr_in sin;
@@ -1385,7 +1393,7 @@ dhcp_openudp(struct interface *ifp)
        if (ifp)
                state->udp_fd = s;
        else
-               udp_fd = s;
+               ctx->udp_fd = s;
        return 0;
 
 eexit:
@@ -1514,7 +1522,7 @@ send_message(struct interface *iface, int type,
 
        /* Ensure sockets are open. */
        if (dhcp_open(iface) == -1) {
-               if (!(options & DHCPCD_TEST))
+               if (!(iface->ctx->options & DHCPCD_TEST))
                        dhcp_drop(iface, "FAIL");
                return;
        }
@@ -1524,7 +1532,8 @@ send_message(struct interface *iface, int type,
         * This could happen if our IP was pulled out from underneath us.
         * Also, we should not unicast from a BOOTP lease. */
        if (state->udp_fd == -1 ||
-           (!(ifo->options & DHCPCD_INFORM) && is_bootp(state->new)))
+           (!(ifo->options & DHCPCD_INFORM) &&
+           is_bootp(iface, state->new)))
        {
                a = state->addr.s_addr;
                state->addr.s_addr = 0;
@@ -1557,10 +1566,10 @@ send_message(struct interface *iface, int type,
                if (r == -1) {
                        syslog(LOG_ERR, "%s: ipv4_sendrawpacket: %m",
                            iface->name);
-                       if (!(options & DHCPCD_TEST))
+                       if (!(iface->ctx->options & DHCPCD_TEST))
                                dhcp_drop(iface, "FAIL");
                        dhcp_close(iface);
-                       eloop_timeout_delete(NULL, iface);
+                       eloop_timeout_delete(iface->ctx->eloop, NULL, iface);
                        callback = NULL;
                }
        }
@@ -1569,7 +1578,7 @@ send_message(struct interface *iface, int type,
        /* Even if we fail to send a packet we should continue as we are
         * as our failure timeouts will change out codepath when needed. */
        if (callback)
-               eloop_timeout_add_tv(&tv, callback, iface);
+               eloop_timeout_add_tv(iface->ctx->eloop, &tv, callback, iface);
 }
 
 static void
@@ -1618,7 +1627,9 @@ dhcp_discover(void *arg)
        /* If we're rebooting and we're not daemonised then we need
         * to shorten the normal timeout to ensure we try correctly
         * for a fallback or IPv4LL address. */
-       if (state->state == DHS_REBOOT && !(options & DHCPCD_DAEMONISED)) {
+       if (state->state == DHS_REBOOT &&
+           !(iface->ctx->options & DHCPCD_DAEMONISED))
+       {
                timeout -= ifo->reboot;
                if (timeout <= 0)
                        timeout = 2;
@@ -1626,17 +1637,17 @@ dhcp_discover(void *arg)
 
        state->state = DHS_DISCOVER;
        state->xid = dhcp_xid(iface);
-       eloop_timeout_delete(NULL, iface);
+       eloop_timeout_delete(iface->ctx->eloop, NULL, iface);
        if (ifo->fallback)
-               eloop_timeout_add_sec(timeout, dhcp_fallback, iface);
+               eloop_timeout_add_sec(iface->ctx->eloop,
+                   timeout, dhcp_fallback, iface);
        else if (ifo->options & DHCPCD_IPV4LL &&
            !IN_LINKLOCAL(htonl(state->addr.s_addr)))
        {
                if (IN_LINKLOCAL(htonl(state->fail.s_addr)))
-                       eloop_timeout_add_sec(RATE_LIMIT_INTERVAL,
-                           ipv4ll_start, iface);
-               else
-                       eloop_timeout_add_sec(timeout, ipv4ll_start, iface);
+                       timeout = RATE_LIMIT_INTERVAL;
+               eloop_timeout_add_sec(iface->ctx->eloop,
+                   timeout, ipv4ll_start, iface);
        }
        if (ifo->options & DHCPCD_REQUEST)
                syslog(LOG_INFO, "%s: soliciting a DHCP lease (requesting %s)",
@@ -1663,7 +1674,7 @@ dhcp_expire(void *arg)
        struct dhcp_state *state = D_STATE(ifp);
 
        syslog(LOG_ERR, "%s: DHCP lease expired", ifp->name);
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        dhcp_drop(ifp, "EXPIRE");
        unlink(state->leasefile);
 
@@ -1708,7 +1719,7 @@ dhcp_rebind(void *arg)
        syslog(LOG_DEBUG, "%s: expire in %"PRIu32" seconds",
            ifp->name, lease->leasetime - lease->rebindtime);
        state->state = DHS_REBIND;
-       eloop_timeout_delete(send_renew, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp);
        state->lease.server.s_addr = 0;
        ifp->options->options &= ~ DHCPCD_CSR_WARNED;
        send_rebind(ifp);
@@ -1730,7 +1741,7 @@ dhcp_bind(void *arg)
        state->old = state->new;
        state->new = state->offer;
        state->offer = NULL;
-       get_lease(lease, state->new);
+       get_lease(iface->ctx, lease, state->new);
        if (ifo->options & DHCPCD_STATIC) {
                syslog(LOG_INFO, "%s: using static address %s/%d",
                    iface->name, inet_ntoa(lease->addr),
@@ -1794,10 +1805,10 @@ dhcp_bind(void *arg)
                            inet_ntoa(lease->addr), lease->leasetime);
                }
        }
-       if (options & DHCPCD_TEST) {
+       if (iface->ctx->options & DHCPCD_TEST) {
                state->reason = "TEST";
                script_runreason(iface, state->reason);
-               eloop_exit(EXIT_SUCCESS);
+               eloop_exit(iface->ctx->eloop, EXIT_SUCCESS);
                return;
        }
        if (state->reason == NULL) {
@@ -1815,16 +1826,19 @@ dhcp_bind(void *arg)
        if (lease->leasetime == ~0U)
                lease->renewaltime = lease->rebindtime = lease->leasetime;
        else {
-               eloop_timeout_add_sec(lease->renewaltime, dhcp_renew, iface);
-               eloop_timeout_add_sec(lease->rebindtime, dhcp_rebind, iface);
-               eloop_timeout_add_sec(lease->leasetime, dhcp_expire, iface);
+               eloop_timeout_add_sec(iface->ctx->eloop,
+                   lease->renewaltime, dhcp_renew, iface);
+               eloop_timeout_add_sec(iface->ctx->eloop,
+                   lease->rebindtime, dhcp_rebind, iface);
+               eloop_timeout_add_sec(iface->ctx->eloop,
+                   lease->leasetime, dhcp_expire, iface);
                syslog(LOG_DEBUG,
                    "%s: renew in %"PRIu32" seconds, rebind in %"PRIu32
                    " seconds",
                    iface->name, lease->renewaltime, lease->rebindtime);
        }
        ipv4_applyaddr(iface);
-       if (daemonise() == 0) {
+       if (daemonise(iface->ctx) == 0) {
                if (!ipv4ll)
                        arp_close(iface);
                state->state = DHS_BOUND;
@@ -1886,7 +1900,7 @@ dhcp_static(struct interface *ifp)
        }
        state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
        if (state->offer) {
-               eloop_timeout_delete(NULL, ifp);
+               eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
                dhcp_bind(ifp);
        }
 }
@@ -1900,7 +1914,7 @@ dhcp_inform(struct interface *ifp)
 
        state = D_STATE(ifp);
        ifo = ifp->options;
-       if (options & DHCPCD_TEST) {
+       if (ifp->ctx->options & DHCPCD_TEST) {
                state->addr.s_addr = ifo->req_addr.s_addr;
                state->net.s_addr = ifo->req_mask.s_addr;
        } else {
@@ -1991,14 +2005,17 @@ dhcp_reboot(struct interface *ifp)
        state->state = DHS_REBOOT;
        state->xid = dhcp_xid(ifp);
        state->lease.server.s_addr = 0;
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        if (ifo->fallback)
-               eloop_timeout_add_sec(ifo->reboot, dhcp_fallback, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   ifo->reboot, dhcp_fallback, ifp);
        else if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo)
-               eloop_timeout_add_sec(ifo->reboot, dhcp_timeout, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   ifo->reboot, dhcp_timeout, ifp);
        else if (!(ifo->options & DHCPCD_INFORM &&
-           options & (DHCPCD_MASTER | DHCPCD_DAEMONISED)))
-               eloop_timeout_add_sec(ifo->reboot, dhcp_expire, ifp);
+           ifp->ctx->options & (DHCPCD_MASTER | DHCPCD_DAEMONISED)))
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   ifo->reboot, dhcp_expire, ifp);
        /* Don't bother ARP checking as the server could NAK us first. */
        if (ifo->options & DHCPCD_INFORM)
                dhcp_inform(ifp);
@@ -2020,7 +2037,7 @@ dhcp_drop(struct interface *ifp, const char *reason)
        dhcp_auth_reset(&state->auth);
        dhcp_close(ifp);
        arp_close(ifp);
-       eloop_timeouts_delete(ifp, dhcp_expire, NULL);
+       eloop_timeouts_delete(ifp->ctx->eloop, ifp, dhcp_expire, NULL);
        if (ifp->options->options & DHCPCD_RELEASE) {
                unlink(state->leasefile);
                if (ifp->carrier != LINK_DOWN &&
@@ -2061,7 +2078,7 @@ log_dhcp1(int lvl, const char *msg,
        int r;
 
        if (strcmp(msg, "NAK:") == 0)
-               a = get_option_string(dhcp, DHO_MESSAGE);
+               a = get_option_string(iface->ctx, dhcp, DHO_MESSAGE);
        else if (ad && dhcp->yiaddr != 0) {
                addr.s_addr = dhcp->yiaddr;
                a = strdup(inet_ntoa(addr));
@@ -2073,7 +2090,7 @@ log_dhcp1(int lvl, const char *msg,
                a = NULL;
 
        tfrom = "from";
-       r = get_option_addr(&addr, dhcp, DHO_SERVERID);
+       r = get_option_addr(iface->ctx, &addr, dhcp, DHO_SERVERID);
        if (dhcp->servername[0] && r == 0) {
                if (a == NULL)
                        syslog(lvl, "%s: %s %s %s `%s'", iface->name, msg,
@@ -2145,11 +2162,11 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
        char *msg;
 
        /* We may have found a BOOTP server */
-       if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1)
+       if (get_option_uint8(iface->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
                type = 0;
 
        /* Authenticate the message */
-       auth = get_option(dhcp, DHO_AUTHENTICATION, &auth_len);
+       auth = get_option(iface->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
        if (auth) {
                if (dhcp_auth_validate(&state->auth, &ifo->auth,
                    (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type,
@@ -2193,10 +2210,12 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
                /* The rebind and expire timings are still the same, we just
                 * enter the renew state early */
                if (state->state == DHS_BOUND) {
-                       eloop_timeout_delete(dhcp_renew, iface);
+                       eloop_timeout_delete(iface->ctx->eloop,
+                           dhcp_renew, iface);
                        dhcp_renew(iface);
                } else {
-                       eloop_timeout_delete(send_inform, iface);
+                       eloop_timeout_delete(iface->ctx->eloop,
+                           send_inform, iface);
                        dhcp_inform(iface);
                }
                return;
@@ -2224,7 +2243,7 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
        if (type == DHCP_NAK) {
                /* For NAK, only check if we require the ServerID */
                if (has_option_mask(ifo->requiremask, DHO_SERVERID) &&
-                   get_option_addr(&addr, dhcp, DHO_SERVERID) == -1)
+                   get_option_addr(iface->ctx, &addr, dhcp, DHO_SERVERID) == -1)
                {
                        log_dhcp(LOG_WARNING, "reject NAK", iface, dhcp, from);
                        return;
@@ -2232,18 +2251,19 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
 
                /* We should restart on a NAK */
                log_dhcp(LOG_WARNING, "NAK:", iface, dhcp, from);
-               if ((msg = get_option_string(dhcp, DHO_MESSAGE))) {
+               if ((msg = get_option_string(iface->ctx, dhcp, DHO_MESSAGE))) {
                        syslog(LOG_WARNING, "%s: message: %s",
                            iface->name, msg);
                        free(msg);
                }
-               if (!(options & DHCPCD_TEST)) {
+               if (!(iface->ctx->options & DHCPCD_TEST)) {
                        dhcp_drop(iface, "NAK");
                        unlink(state->leasefile);
                }
 
                /* If we constantly get NAKS then we should slowly back off */
-               eloop_timeout_add_sec(state->nakoff, dhcp_discover, iface);
+               eloop_timeout_add_sec(iface->ctx->eloop,
+                   state->nakoff, dhcp_discover, iface);
                if (state->nakoff == 0)
                        state->nakoff = 1;
                else {
@@ -2257,30 +2277,33 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
        /* DHCP Auto-Configure, RFC 2563 */
        if (type == DHCP_OFFER && dhcp->yiaddr == 0) {
                log_dhcp(LOG_WARNING, "no address given", iface, dhcp, from);
-               if ((msg = get_option_string(dhcp, DHO_MESSAGE))) {
+               if ((msg = get_option_string(iface->ctx, dhcp, DHO_MESSAGE))) {
                        syslog(LOG_WARNING, "%s: message: %s",
                            iface->name, msg);
                        free(msg);
                }
                if (state->state == DHS_DISCOVER &&
-                   get_option_uint8(&tmp, dhcp, DHO_AUTOCONFIGURE) == 0)
+                   get_option_uint8(iface->ctx, &tmp, dhcp,
+                   DHO_AUTOCONFIGURE) == 0)
                {
                        switch (tmp) {
                        case 0:
                                log_dhcp(LOG_WARNING, "IPv4LL disabled from",
                                    iface, dhcp, from);
                                dhcp_close(iface);
-                               eloop_timeout_delete(NULL, iface);
-                               eloop_timeout_add_sec(DHCP_MAX, dhcp_discover,
+                               eloop_timeout_delete(iface->ctx->eloop,
+                                   NULL, iface);
+                               eloop_timeout_add_sec(iface->ctx->eloop,
+                                   DHCP_MAX, dhcp_discover,
                                    iface);
                                break;
                        case 1:
                                log_dhcp(LOG_WARNING, "IPv4LL enabled from",
                                    iface, dhcp, from);
-                               eloop_timeout_delete(NULL, iface);
+                               eloop_timeout_delete(iface->ctx->eloop, NULL, iface);
                                if (IN_LINKLOCAL(htonl(state->addr.s_addr)))
-                                       eloop_timeout_add_sec(DHCP_MAX,
-                                           dhcp_discover, iface);
+                                       eloop_timeout_add_sec(iface->ctx->eloop,
+                                           DHCP_MAX, dhcp_discover, iface);
                                else
                                        ipv4ll_start(iface);
                                break;
@@ -2297,7 +2320,7 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
        /* Ensure that all required options are present */
        for (i = 1; i < 255; i++) {
                if (has_option_mask(ifo->requiremask, i) &&
-                   get_option_uint8(&tmp, dhcp, i) != 0)
+                   get_option_uint8(iface->ctx, &tmp, dhcp, i) != 0)
                {
                        /* If we are bootp, then ignore the need for serverid.
                         * To ignore bootp, require dhcp_message_type. */
@@ -2325,23 +2348,24 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
                lease->addr.s_addr = dhcp->yiaddr;
                lease->cookie = dhcp->cookie;
                if (type == 0 ||
-                   get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
+                   get_option_addr(iface->ctx,
+                   &lease->server, dhcp, DHO_SERVERID) != 0)
                        lease->server.s_addr = INADDR_ANY;
                log_dhcp(LOG_INFO, "offered", iface, dhcp, from);
                free(state->offer);
                state->offer = dhcp;
                *dhcpp = NULL;
-               if (options & DHCPCD_TEST) {
+               if (iface->ctx->options & DHCPCD_TEST) {
                        free(state->old);
                        state->old = state->new;
                        state->new = state->offer;
                        state->offer = NULL;
                        state->reason = "TEST";
                        script_runreason(iface, state->reason);
-                       eloop_exit(EXIT_SUCCESS);
+                       eloop_exit(iface->ctx->eloop, EXIT_SUCCESS);
                        return;
                }
-               eloop_timeout_delete(send_discover, iface);
+               eloop_timeout_delete(iface->ctx->eloop, send_discover, iface);
                /* We don't request BOOTP addresses */
                if (type) {
                        /* We used to ARP check here, but that seems to be in
@@ -2390,7 +2414,7 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
        }
 
        lease->frominfo = 0;
-       eloop_timeout_delete(NULL, iface);
+       eloop_timeout_delete(iface->ctx->eloop, NULL, iface);
 
        if (ifo->options & DHCPCD_ARP &&
            state->addr.s_addr != state->offer->yiaddr)
@@ -2488,10 +2512,12 @@ dhcp_handlepacket(void *arg)
         * the first one fails for any reason, we can use the next. */
        for(;;) {
                bytes = ipv4_getrawpacket(iface, ETHERTYPE_IP,
-                   packet, udp_dhcp_len, &partialcsum);
+                   iface->ctx->packet, udp_dhcp_len, &partialcsum);
                if (bytes == 0 || bytes == -1)
                        break;
-               if (valid_udp_packet(packet, bytes, &from, partialcsum) == -1) {
+               if (valid_udp_packet(iface->ctx->packet, bytes,
+                       &from, partialcsum) == -1)
+               {
                        syslog(LOG_ERR, "%s: invalid UDP packet from %s",
                            iface->name, inet_ntoa(from));
                        continue;
@@ -2517,7 +2543,7 @@ dhcp_handlepacket(void *arg)
                            "%s: server %s is not destination",
                            iface->name, inet_ntoa(from));
                }
-               bytes = get_udp_data(&pp, packet);
+               bytes = get_udp_data(&pp, iface->ctx->packet);
                if ((size_t)bytes > sizeof(*dhcp)) {
                        syslog(LOG_ERR,
                            "%s: packet greater than DHCP size from %s",
@@ -2541,9 +2567,12 @@ dhcp_handlepacket(void *arg)
                if (iface->hwlen <= sizeof(dhcp->chaddr) &&
                    memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen))
                {
+                       char buf[sizeof(dhcp->chaddr) * 3];
+
                        syslog(LOG_DEBUG, "%s: xid 0x%x is not for hwaddr %s",
                            iface->name, ntohl(dhcp->xid),
-                           hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr)));
+                           hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr),
+                               buf, sizeof(buf)));
                        continue;
                }
                dhcp_handledhcp(iface, &dhcp, &from);
@@ -2556,21 +2585,29 @@ dhcp_handlepacket(void *arg)
 static void
 dhcp_handleudp(void *arg)
 {
-       int fd;
+       struct dhcpcd_ctx *ctx;
+       uint8_t buffer[sizeof(struct dhcp_message)];
+
+       ctx = arg;
+
+       /* Just read what's in the UDP fd and discard it as we always read
+        * from the raw fd */
+       read(ctx->udp_fd, buffer, sizeof(buffer));
+}
+
+static void
+dhcp_handleifudp(void *arg)
+{
        const struct interface *ifp;
        const struct dhcp_state *state;
        uint8_t buffer[sizeof(struct dhcp_message)];
 
-       if (arg) {
-               ifp = arg;
-               state = D_CSTATE(ifp);
-               fd = state->udp_fd;
-       } else
-               fd = udp_fd;
+       ifp = arg;
+       state = D_CSTATE(ifp);
 
        /* Just read what's in the UDP fd and discard it as we always read
         * from the raw fd */
-       read(fd, buffer, sizeof(buffer));
+       read(state->udp_fd, buffer, sizeof(buffer));
 }
 
 static int
@@ -2578,9 +2615,9 @@ dhcp_open(struct interface *ifp)
 {
        struct dhcp_state *state;
 
-       if (packet == NULL) {
-               packet = malloc(udp_dhcp_len);
-               if (packet == NULL) {
+       if (ifp->ctx->packet == NULL) {
+               ifp->ctx->packet = malloc(udp_dhcp_len);
+               if (ifp->ctx->packet == NULL) {
                        syslog(LOG_ERR, "%s: %m", __func__);
                        return -1;
                }
@@ -2593,7 +2630,8 @@ dhcp_open(struct interface *ifp)
                        syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name);
                        return -1;
                }
-               eloop_event_add(state->raw_fd, dhcp_handlepacket, ifp);
+               eloop_event_add(ifp->ctx->eloop,
+                   state->raw_fd, dhcp_handlepacket, ifp);
        }
        if (state->udp_fd == -1 &&
            state->addr.s_addr != 0 &&
@@ -2601,12 +2639,13 @@ dhcp_open(struct interface *ifp)
            (state->new->cookie == htonl(MAGIC_COOKIE) ||
            ifp->options->options & DHCPCD_INFORM))
        {
-               if (dhcp_openudp(ifp) == -1 && errno != EADDRINUSE) {
+               if (dhcp_openudp(ifp->ctx, ifp) == -1 && errno != EADDRINUSE) {
                        syslog(LOG_ERR, "%s: dhcp_openudp: %m", ifp->name);
                        return -1;
                }
                if (state->udp_fd != -1)
-                       eloop_event_add(state->udp_fd, dhcp_handleudp, ifp);
+                       eloop_event_add(ifp->ctx->eloop,
+                           state->udp_fd, dhcp_handleifudp, ifp);
        }
        return 0;
 }
@@ -2614,17 +2653,23 @@ dhcp_open(struct interface *ifp)
 int
 dhcp_dump(const char *ifname)
 {
+       struct dhcpcd_ctx ctx;
        struct interface *ifp;
        struct dhcp_state *state;
+       int r;
 
-       ifaces = malloc(sizeof(*ifaces));
-       if (ifaces == NULL)
+       ifp = NULL;
+       state = NULL;
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.ifaces = malloc(sizeof(*ctx.ifaces));
+       if (ctx.ifaces == NULL)
                goto eexit;
-       TAILQ_INIT(ifaces);
+       TAILQ_INIT(ctx.ifaces);
        ifp = calloc(1, sizeof(*ifp));
        if (ifp == NULL)
                goto eexit;
-       TAILQ_INSERT_HEAD(ifaces, ifp, next);
+       ifp->ctx = &ctx;
+       TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
        ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
        if (state == NULL)
                goto eexit;
@@ -2634,8 +2679,7 @@ dhcp_dump(const char *ifname)
        strlcpy(ifp->name, ifname, sizeof(ifp->name));
        snprintf(state->leasefile, sizeof(state->leasefile),
            LEASEFILE, ifp->name);
-       strlcpy(ifp->options->script, if_options->script,
-           sizeof(ifp->options->script));
+       strlcpy(ifp->options->script, SCRIPT, sizeof(ifp->options->script));
        state->new = read_lease(ifp);
        if (state->new == NULL && errno == ENOENT) {
                strlcpy(state->leasefile, ifname, sizeof(state->leasefile));
@@ -2644,20 +2688,35 @@ dhcp_dump(const char *ifname)
        if (state->new == NULL) {
                if (errno == ENOENT)
                        syslog(LOG_ERR, "%s: no lease to dump", ifname);
-               return -1;
+               r = -1;
+               goto cexit;
        }
        state->reason = "DUMP";
-       return script_runreason(ifp, state->reason);
+       r = script_runreason(ifp, state->reason);
+       goto cexit;
 
 eexit:
        syslog(LOG_ERR, "%s: %m", __func__);
-       return -1;
+       r = -1;
+
+cexit:
+       if (state) {
+               free(state->new);
+               free(state);
+       }
+       if (ifp) {
+               free(ifp->options);
+               free(ifp);
+       }
+       free(ctx.ifaces);
+       return r;
 }
 
 void
 dhcp_free(struct interface *ifp)
 {
        struct dhcp_state *state = D_STATE(ifp);
+       struct dhcpcd_ctx *ctx;
 
        if (state) {
                free(state->old);
@@ -2669,25 +2728,26 @@ dhcp_free(struct interface *ifp)
                ifp->if_data[IF_DATA_DHCP] = NULL;
        }
 
+       ctx = ifp->ctx;
        /* If we don't have any more DHCP enabled interfaces,
         * close the global socket and release resources */
-       if (ifaces) {
-               TAILQ_FOREACH(ifp, ifaces, next) {
+       if (ctx->ifaces) {
+               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                        if (D_STATE(ifp))
                                break;
                }
        }
        if (ifp == NULL) {
-               if (udp_fd != -1) {
-                       close(udp_fd);
-                       eloop_event_delete(udp_fd);
-                       udp_fd = -1;
+               if (ctx->udp_fd != -1) {
+                       close(ctx->udp_fd);
+                       eloop_event_delete(ctx->eloop, ctx->udp_fd);
+                       ctx->udp_fd = -1;
                }
 
-               free(packet);
-               free(opt_buffer);
-               packet = NULL;
-               opt_buffer = NULL;
+               free(ctx->packet);
+               free(ctx->opt_buffer);
+               ctx->packet = NULL;
+               ctx->opt_buffer = NULL;
        }
 }
 
@@ -2697,6 +2757,7 @@ dhcp_init(struct interface *ifp)
        struct dhcp_state *state;
        const struct if_options *ifo;
        size_t len;
+       char buf[(sizeof(ifo->clientid) - 1) * 3];
 
        state = D_STATE(ifp);
        if (state == NULL) {
@@ -2730,13 +2791,14 @@ dhcp_init(struct interface *ifp)
                memcpy(state->clientid, ifo->clientid, ifo->clientid[0] + 1);
        } else if (ifo->options & DHCPCD_CLIENTID) {
                if (ifo->options & DHCPCD_DUID) {
-                       state->clientid = malloc(duid_len + 6);
+                       state->clientid = malloc(ifp->ctx->duid_len + 6);
                        if (state->clientid == NULL)
                                goto eexit;
-                       state->clientid[0] = duid_len + 5;
+                       state->clientid[0] = ifp->ctx->duid_len + 5;
                        state->clientid[1] = 255; /* RFC 4361 */
                        memcpy(state->clientid + 2, ifo->iaid, 4);
-                       memcpy(state->clientid + 6, duid, duid_len);
+                       memcpy(state->clientid + 6, ifp->ctx->duid,
+                           ifp->ctx->duid_len);
                } else {
                        len = ifp->hwlen + 1;
                        state->clientid = malloc(len + 1);
@@ -2756,10 +2818,11 @@ dhcp_init(struct interface *ifp)
 
        if (ifo->options & DHCPCD_CLIENTID)
                syslog(LOG_DEBUG, "%s: using ClientID %s", ifp->name,
-                   hwaddr_ntoa(state->clientid + 1, state->clientid[0]));
+                   hwaddr_ntoa(state->clientid + 1, state->clientid[0],
+                       buf, sizeof(buf)));
        else if (ifp->hwlen)
                syslog(LOG_DEBUG, "%s: using hwaddr %s", ifp->name,
-                   hwaddr_ntoa(ifp->hwaddr, ifp->hwlen));
+                   hwaddr_ntoa(ifp->hwaddr, ifp->hwlen, buf, sizeof(buf)));
        return 0;
 
 eexit:
@@ -2782,8 +2845,9 @@ dhcp_start(struct interface *ifp)
 
        /* Listen on *.*.*.*:bootpc so that the kernel never sends an
         * ICMP port unreachable message back to the DHCP server */
-       if (udp_fd == -1 && dhcp_openudp(NULL) != -1)
-               eloop_event_add(udp_fd, dhcp_handleudp, NULL);
+       if (ifp->ctx->udp_fd == -1 && dhcp_openudp(ifp->ctx, NULL) != -1)
+               eloop_event_add(ifp->ctx->eloop,
+                   ifp->ctx->udp_fd, dhcp_handleudp, ifp->ctx);
 
        if (dhcp_init(ifp) == -1) {
                syslog(LOG_ERR, "%s: dhcp_init: %m", ifp->name);
@@ -2819,15 +2883,15 @@ dhcp_start(struct interface *ifp)
                syslog(LOG_WARNING, "%s: needs a clientid to configure",
                    ifp->name);
                dhcp_drop(ifp, "FAIL");
-               eloop_timeout_delete(NULL, ifp);
+               eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
                return;
        }
        /* We don't want to read the old lease if we NAK an old test */
-       nolease = state->offer && options & DHCPCD_TEST;
+       nolease = state->offer && ifp->ctx->options & DHCPCD_TEST;
        if (!nolease)
                state->offer = read_lease(ifp);
        if (state->offer) {
-               get_lease(&state->lease, state->offer);
+               get_lease(ifp->ctx, &state->lease, state->offer);
                state->lease.frominfo = 1;
                if (state->offer->cookie == 0) {
                        if (state->offer->yiaddr == state->addr.s_addr) {
@@ -2931,7 +2995,7 @@ dhcp_handleifa(int type, struct interface *ifp,
                                dhcp_message_add_addr(state->new, i, *dst);
        }
        state->reason = "STATIC";
-       ipv4_buildroutes();
+       ipv4_buildroutes(ifp->ctx);
        script_runreason(ifp, state->reason);
        if (ifo->options & DHCPCD_INFORM) {
                state->state = DHS_INFORM;
diff --git a/dhcp.h b/dhcp.h
index bf05441d9a10d40888bc6b7e75dafa7f76a1f6cd..c9eaf46926acebf3d5e8b79f26066357201cd4e1 100644 (file)
--- a/dhcp.h
+++ b/dhcp.h
@@ -246,19 +246,16 @@ struct dhcp_state {
 #include "net.h"
 
 #ifdef INET
-extern struct dhcp_opt *dhcp_opts;
-extern size_t dhcp_opts_len;
-
 char *decode_rfc3361(int dl, const uint8_t *data);
 ssize_t decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p);
 ssize_t decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p);
 
-void dhcp_printoptions(void);
-char *get_option_string(const struct dhcp_message *, uint8_t);
-int get_option_addr(struct in_addr *, const struct dhcp_message *, uint8_t);
-#define is_bootp(m) (m &&                                              \
+void dhcp_printoptions(const struct dhcpcd_ctx *);
+int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
+    const struct dhcp_message *, uint8_t);
+#define is_bootp(i, m) ((m) &&                                         \
            !IN_LINKLOCAL(htonl((m)->yiaddr)) &&                        \
-           get_option_uint8(NULL, m, DHO_MESSAGETYPE) == -1)
+           get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
 struct rt_head *get_option_routes(struct interface *,
     const struct dhcp_message *);
 ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
@@ -274,7 +271,6 @@ int valid_dhcp_packet(unsigned char *);
 
 ssize_t write_lease(const struct interface *, const struct dhcp_message *);
 struct dhcp_message *read_lease(struct interface *);
-void get_lease(struct dhcp_lease *, const struct dhcp_message *);
 
 void dhcp_handleifa(int, struct interface *,
     const struct in_addr *, const struct in_addr *, const struct in_addr *);
diff --git a/dhcp6.c b/dhcp6.c
index 033036b8a805ee3f8dd5e050bf0b72133fa5008a..4eb99541933170980becd874780ff4a3c8cb9b08 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
 /* Unsure if I want this */
 //#define VENDOR_SPLIT
 
-static int sock = -1;
-static const struct in6_addr in6addr_linklocal_alldhcp =
-    IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
-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 char *status;
-static size_t status_len;
-
 struct dhcp6_op {
        uint16_t type;
        const char *name;
@@ -100,9 +85,6 @@ static const struct dhcp6_op dhcp6_ops[] = {
        { 0, NULL }
 };
 
-struct dhcp_opt *dhcp6_opts = NULL;
-size_t dhcp6_opts_len = 0;
-
 struct dhcp_compat {
        uint8_t dhcp_opt;
        uint16_t dhcp6_opt;
@@ -132,48 +114,16 @@ static const char * const dhcp6_statuses[] = {
 };
 
 void
-dhcp6_printoptions(void)
+dhcp6_printoptions(const struct dhcpcd_ctx *ctx)
 {
        size_t i;
        const struct dhcp_opt *opt;
 
-       for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++)
+       for (i = 0, opt = ctx->dhcp6_opts;
+           i < ctx->dhcp6_opts_len; i++, opt++)
                printf("%05d %s\n", opt->option, opt->var);
 }
 
-static int
-dhcp6_init(void)
-{
-       int len;
-
-       len = CMSG_SPACE(sizeof(struct in6_pktinfo));
-       sndbuf = calloc(1, len);
-       if (sndbuf == NULL)
-               return -1;
-       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) {
-               free(sndbuf);
-               sndbuf = NULL;
-               return -1;
-       }
-       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);
-
-       return 0;
-}
-
 static size_t
 dhcp6_makevendor(struct dhcp6_option *o, const struct interface *ifp)
 {
@@ -257,7 +207,8 @@ dhcp6_findoption(int code, const uint8_t *d, ssize_t len)
 }
 
 static const uint8_t *
-dhcp6_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
+dhcp6_getoption(struct dhcpcd_ctx *ctx,
+    unsigned int *os, unsigned int *code, unsigned int *len,
     const uint8_t *od, unsigned int ol, struct dhcp_opt **oopt)
 {
        const struct dhcp6_option *o;
@@ -280,7 +231,9 @@ dhcp6_getoption(unsigned int *os, unsigned int *code, unsigned int *len,
        } else
                o = NULL;
 
-       for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++) {
+       for (i = 0, opt = ctx->dhcp6_opts;
+           i < ctx->dhcp6_opts_len; i++, opt++)
+       {
                if (opt->option == *code) {
                        *oopt = opt;
                        break;
@@ -354,12 +307,13 @@ dhcp6_makemessage(struct interface *ifp)
        int auth_len;
        uint8_t u8;
        uint16_t *u16, n_options, type;
-       const struct if_options *ifo;
+       struct if_options *ifo;
        const struct dhcp_opt *opt;
        uint8_t IA, *p;
        uint32_t u32;
        const struct ipv6_addr *ap;
-       const char *hostname = NULL; /* assignment just to appease GCC*/
+       char hbuf[HOSTNAME_MAX_LEN + 1];
+       const char *hostname;
        int fqdn;
 
        state = D6_STATE(ifp);
@@ -379,18 +333,22 @@ dhcp6_makemessage(struct interface *ifp)
        }
        if (fqdn != FQDN_DISABLE) {
                if (ifo->hostname[0] == '\0')
-                       hostname = get_hostname(ifo->options &
-                           DHCPCD_HOSTNAME_SHORT ? 1 : 0);
+                       hostname = get_hostname(hbuf, sizeof(hbuf),
+                           ifo->options & DHCPCD_HOSTNAME_SHORT ? 1 : 0);
                else
                        hostname = ifo->hostname;
-       }
+       } else
+               hostname = NULL; /* appearse gcc */
 
        /* Work out option size first */
        n_options = 0;
        len = 0;
        si = NULL;
        if (state->state != DH6S_RELEASE) {
-               for (l = 0, opt = dhcp6_opts; l < dhcp6_opts_len ; l++, opt++) {
+               for (l = 0, opt = ifp->ctx->dhcp6_opts;
+                   l < ifp->ctx->dhcp6_opts_len;
+                   l++, opt++)
+               {
                        if (!(opt->type & NOREQ) &&
                            (opt->type & REQUEST ||
                            has_option_mask(ifo->requestmask6, opt->option)))
@@ -411,7 +369,7 @@ dhcp6_makemessage(struct interface *ifp)
        }
 
        len += sizeof(*state->send);
-       len += sizeof(*o) + duid_len;
+       len += sizeof(*o) + ifp->ctx->duid_len;
        len += sizeof(*o) + sizeof(uint16_t); /* elapsed */
        len += sizeof(*o) + dhcp6_makevendor(NULL, ifp);
 
@@ -466,7 +424,7 @@ dhcp6_makemessage(struct interface *ifp)
        }
 
        if (state->state == DH6S_DISCOVER &&
-           !(options & DHCPCD_TEST) &&
+           !(ifp->ctx->options & DHCPCD_TEST) &&
            has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
                len += sizeof(*o);
 
@@ -534,8 +492,8 @@ dhcp6_makemessage(struct interface *ifp)
 
        o = D6_FIRST_OPTION(state->send);
        o->code = htons(D6_OPTION_CLIENTID);
-       o->len = htons(duid_len);
-       memcpy(D6_OPTION_DATA(o), duid, duid_len);
+       o->len = htons(ifp->ctx->duid_len);
+       memcpy(D6_OPTION_DATA(o), ifp->ctx->duid, ifp->ctx->duid_len);
 
        if (si) {
                o = D6_NEXT_OPTION(o);
@@ -552,7 +510,7 @@ dhcp6_makemessage(struct interface *ifp)
        dhcp6_makevendor(o, ifp);
 
        if (state->state == DH6S_DISCOVER &&
-           !(options & DHCPCD_TEST) &&
+           !(ifp->ctx->options & DHCPCD_TEST) &&
            has_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT))
        {
                o = D6_NEXT_OPTION(o);
@@ -654,8 +612,8 @@ dhcp6_makemessage(struct interface *ifp)
                        o->code = htons(D6_OPTION_ORO);
                        o->len = 0;
                        u16 = (uint16_t *)(void *)D6_OPTION_DATA(o);
-                       for (l = 0, opt = dhcp6_opts;
-                           l < dhcp6_opts_len;
+                       for (l = 0, opt = ifp->ctx->dhcp6_opts;
+                           l < ifp->ctx->dhcp6_opts_len;
                            l++, opt++)
                        {
                                if (!(opt->type & NOREQ) &&
@@ -703,7 +661,7 @@ dhcp6_freedrop_addrs(struct interface *ifp, int drop,
        if (state) {
                ipv6_freedrop_addrs(&state->addrs, drop, ifd);
                if (drop)
-                       ipv6_buildroutes();
+                       ipv6_buildroutes(ifp->ctx);
        }
 }
 
@@ -711,8 +669,8 @@ static void dhcp6_delete_delegates(struct interface *ifp)
 {
        struct interface *ifp0;
 
-       if (ifaces) {
-               TAILQ_FOREACH(ifp0, ifaces, next) {
+       if (ifp->ctx->ifaces) {
+               TAILQ_FOREACH(ifp0, ifp->ctx->ifaces, next) {
                        if (ifp0 != ifp)
                                dhcp6_freedrop_addrs(ifp0, 1, ifp);
                }
@@ -744,6 +702,7 @@ static int
 dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
 {
        struct dhcp6_state *state;
+       struct ipv6_ctx *ctx;
        struct sockaddr_in6 to;
        struct cmsghdr *cm;
        struct in6_pktinfo pi;
@@ -752,6 +711,7 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
        suseconds_t ms;
        uint8_t neg;
        const char *broad_uni;
+       const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
 
        memset(&to, 0, sizeof(to));
        to.sin6_family = AF_INET6;
@@ -768,7 +728,7 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
            (state->state == DH6S_REQUEST &&
            (!IN6_IS_ADDR_LINKLOCAL(&state->unicast) || !ipv6_linklocal(ifp))))
        {
-               to.sin6_addr = in6addr_linklocal_alldhcp;
+               to.sin6_addr = alldhcp;
                broad_uni = "broadcasting";
        } else {
                to.sin6_addr = state->unicast;
@@ -852,7 +812,8 @@ logsend:
                /* Wait the initial delay */
                if (state->IMD) {
                        state->IMD = 0;
-                       eloop_timeout_add_tv(&state->RT, callback, ifp);
+                       eloop_timeout_add_tv(ifp->ctx->eloop,
+                           &state->RT, callback, ifp);
                        return 0;
                }
        }
@@ -866,13 +827,14 @@ logsend:
                return -1;
        }
 
+       ctx = ifp->ctx->ipv6;
        to.sin6_scope_id = ifp->index;
-       sndhdr.msg_name = (caddr_t)&to;
-       sndhdr.msg_iov[0].iov_base = (caddr_t)state->send;
-       sndhdr.msg_iov[0].iov_len = state->send_len;
+       ctx->sndhdr.msg_name = (caddr_t)&to;
+       ctx->sndhdr.msg_iov[0].iov_base = (caddr_t)state->send;
+       ctx->sndhdr.msg_iov[0].iov_len = state->send_len;
 
        /* Set the outbound interface */
-       cm = CMSG_FIRSTHDR(&sndhdr);
+       cm = CMSG_FIRSTHDR(&ctx->sndhdr);
        cm->cmsg_level = IPPROTO_IPV6;
        cm->cmsg_type = IPV6_PKTINFO;
        cm->cmsg_len = CMSG_LEN(sizeof(pi));
@@ -880,7 +842,7 @@ logsend:
        pi.ipi6_ifindex = ifp->index;
        memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
 
-       if (sendmsg(sock, &sndhdr, 0) == -1) {
+       if (sendmsg(ctx->dhcp_fd, &ctx->sndhdr, 0) == -1) {
                syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
                ifp->options->options &= ~DHCPCD_IPV6;
                dhcp6_drop(ifp, "EXPIRE6");
@@ -890,10 +852,11 @@ logsend:
        state->RTC++;
        if (callback) {
                if (state->MRC == 0 || state->RTC < state->MRC)
-                       eloop_timeout_add_tv(&state->RT, callback, ifp);
+                       eloop_timeout_add_tv(ifp->ctx->eloop,
+                           &state->RT, callback, ifp);
                else if (state->MRC != 0 && state->MRCcallback)
-                       eloop_timeout_add_tv(&state->RT, state->MRCcallback,
-                           ifp);
+                       eloop_timeout_add_tv(ifp->ctx->eloop,
+                           &state->RT, state->MRCcallback, ifp);
                else
                        syslog(LOG_WARNING, "%s: sent %d times with no reply",
                            ifp->name, state->RTC);
@@ -991,7 +954,7 @@ dhcp6_startdiscover(void *arg)
        state->MRT = state->sol_max_rt;
        state->MRC = 0;
 
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        free(state->new);
        state->new = NULL;
        state->new_len = 0;
@@ -1053,7 +1016,7 @@ dhcp6_startrebind(void *arg)
        struct dhcp6_state *state;
 
        ifp = arg;
-       eloop_timeout_delete(dhcp6_sendrenew, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrenew, ifp);
        state = D6_STATE(ifp);
        if (state->state == DH6S_RENEW)
                syslog(LOG_WARNING, "%s: failed to renew DHCPv6, rebinding",
@@ -1080,7 +1043,8 @@ dhcp6_startrebind(void *arg)
 
        /* RFC 3633 section 12.1 */
        if (ifp->options->ia_type == D6_OPTION_IA_PD)
-               eloop_timeout_add_sec(CNF_MAX_RD, dhcp6_failrebind, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   CNF_MAX_RD, dhcp6_failrebind, ifp);
 }
 
 
@@ -1089,7 +1053,7 @@ dhcp6_startrequest(struct interface *ifp)
 {
        struct dhcp6_state *state;
 
-       eloop_timeout_delete(dhcp6_senddiscover, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp);
        state = D6_STATE(ifp);
        state->state = DH6S_REQUEST;
        state->RTC = 0;
@@ -1126,7 +1090,8 @@ dhcp6_startconfirm(struct interface *ifp)
                return;
        }
        dhcp6_sendconfirm(ifp);
-       eloop_timeout_add_sec(CNF_MAX_RD, dhcp6_failconfirm, ifp);
+       eloop_timeout_add_sec(ifp->ctx->eloop,
+           CNF_MAX_RD, dhcp6_failconfirm, ifp);
 }
 
 static void
@@ -1160,7 +1125,7 @@ dhcp6_startexpire(void *arg)
        struct interface *ifp;
 
        ifp = arg;
-       eloop_timeout_delete(dhcp6_sendrebind, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp);
 
        syslog(LOG_ERR, "%s: DHCPv6 lease expired", ifp->name);
        dhcp6_freedrop_addrs(ifp, 1, NULL);
@@ -1196,27 +1161,35 @@ dhcp6_startrelease(struct interface *ifp)
                dhcp6_sendmessage(ifp, NULL);
 }
 
-static int dhcp6_getstatus(const struct dhcp6_option *o)
+static int
+dhcp6_checkstatusok(const struct interface *ifp,
+    const struct dhcp6_message *m, const uint8_t *p, size_t len)
 {
+       const struct dhcp6_option *o;
        uint16_t code;
-       char *nstatus;
-       size_t len;
-       const uint8_t *p;
+       char *status;
+
+       if (p)
+               o = dhcp6_findoption(D6_OPTION_STATUS_CODE, p, len);
+       else
+               o = dhcp6_getmoption(D6_OPTION_STATUS_CODE, m, len);
+       if (o == NULL) {
+               //syslog(LOG_DEBUG, "%s: no status", ifp->name);
+               return 0;
+       }
 
        len = ntohs(o->len);
        if (len < sizeof(code)) {
-               syslog(LOG_ERR, "status truncated");
-               return -1;
-       }
-       if (ntohs(o->code) != D6_OPTION_STATUS_CODE) {
-               /* unlikely */
-               syslog(LOG_ERR, "not a status");
+               syslog(LOG_ERR, "%s: status truncated", ifp->name);
                return -1;
        }
+
        p = D6_COPTION_DATA(o);
-       len = ntohs(o->len);
        memcpy(&code, p, sizeof(code));
        code = ntohs(code);
+       if (code == D6_STATUS_OK)
+               return 1;
+
        len -= sizeof(code);
 
        if (len == 0) {
@@ -1225,45 +1198,19 @@ static int dhcp6_getstatus(const struct dhcp6_option *o)
                        len = strlen((const char *)p);
                } else
                        p = NULL;
-       } else {
-               p = D6_COPTION_DATA(o) + sizeof(uint16_t);
-       }
-       if (status == NULL || len + 1 > status_len) {
-               status_len = len;
-               nstatus = realloc(status, status_len + 1);
-               if (nstatus == NULL) {
-                       syslog(LOG_ERR, "%s: %m", __func__);
-                       free(status);
-               }
-               status = nstatus;
-       }
-       if (status) {
-               memcpy(status, p, len);
-               status[len] = '\0';
-       }
-       return code;
-}
-
-static int
-dhcp6_checkstatusok(const struct interface *ifp,
-    const struct dhcp6_message *m, const uint8_t *p, size_t len)
-{
-       const struct dhcp6_option *o;
+       } else
+               p += sizeof(code);
 
-       if (p)
-               o = dhcp6_findoption(D6_OPTION_STATUS_CODE, p, len);
-       else
-               o = dhcp6_getmoption(D6_OPTION_STATUS_CODE, m, len);
-       if (o == NULL) {
-               //syslog(LOG_DEBUG, "%s: no status", ifp->name);
-               return 0;
-       }
-       if (dhcp6_getstatus(o) != D6_STATUS_OK) {
-               syslog(LOG_ERR, "%s: DHCPv6 REPLY: %s", ifp->name, status);
+       status = malloc(len + 1);
+       if (status == NULL) {
+               syslog(LOG_ERR, "%s: %m", __func__);
                return -1;
        }
-       //syslog(LOG_DEBUG, "%s: status: %s", ifp->name, status);
-       return 1;
+       memcpy(status, p, len);
+       status[len] = '\0';
+       syslog(LOG_ERR, "%s: DHCPv6 REPLY: %s", ifp->name, status);
+       free(status);
+       return -1;
 }
 
 static struct ipv6_addr *
@@ -1288,11 +1235,11 @@ dhcp6_findaddr(struct interface *ifp, const struct in6_addr *addr)
 }
 
 int
-dhcp6_addrexists(const struct ipv6_addr *addr)
+dhcp6_addrexists(struct dhcpcd_ctx *ctx, const struct ipv6_addr *addr)
 {
        struct interface *ifp;
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                if (dhcp6_findaddr(ifp, addr == NULL ? NULL : &addr->addr))
                        return 1;
        }
@@ -1336,7 +1283,7 @@ dhcp6_dadcallback(void *arg)
                                syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
                                    ifp->name);
                                script_runreason(ifp, state->reason);
-                               daemonise();
+                               daemonise(ifp->ctx);
                        }
                }
        }
@@ -1594,8 +1541,8 @@ dhcp6_findia(struct interface *ifp, const uint8_t *d, size_t l,
                if (ap->flags & IPV6_AF_STALE) {
                        TAILQ_REMOVE(&state->addrs, ap, next);
                        if (ap->dadcallback)
-                               eloop_q_timeout_delete(0, NULL,
-                                   ap->dadcallback);
+                               eloop_q_timeout_delete(ap->iface->ctx->eloop,
+                                   0, NULL, ap->dadcallback);
                        free(ap);
                }
        }
@@ -1742,7 +1689,7 @@ dhcp6_startinit(struct interface *ifp)
        state->state = DH6S_INIT;
        state->expire = ND6_INFINITE_LIFETIME;
        state->lowpl = ND6_INFINITE_LIFETIME;
-       if (!(options & DHCPCD_TEST) &&
+       if (!(ifp->ctx->options & DHCPCD_TEST) &&
            ifp->options->ia_type != D6_OPTION_IA_TA &&
            ifp->options->reboot != 0)
        {
@@ -1763,7 +1710,7 @@ dhcp6_startinit(struct interface *ifp)
 }
 
 static uint32_t
-dhcp6_findsla(void)
+dhcp6_findsla(const struct dhcpcd_ctx *ctx)
 {
        uint32_t sla;
        const struct interface *ifp;
@@ -1772,7 +1719,7 @@ dhcp6_findsla(void)
        /* Slow, but finding the lowest free SLA is needed if we get a
         * /62 or /63 prefix from upstream */
        for (sla = 0; sla < UINT32_MAX; sla++) {
-               TAILQ_FOREACH(ifp, ifaces, next) {
+               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                        state = D6_CSTATE(ifp);
                        if (state && state->sla_set && state->sla == sla)
                                break;
@@ -1813,7 +1760,7 @@ dhcp6_delegate_addr(struct interface *ifp, const struct ipv6_addr *prefix,
        if (sla == NULL || sla->sla_set == 0) {
                if (!state->sla_set) {
                        errno = 0;
-                       state->sla = dhcp6_findsla();
+                       state->sla = dhcp6_findsla(ifp->ctx);
                        if (errno) {
                                syslog(LOG_ERR, "%s: dhcp6_find_sla: %m",
                                    ifp->name);
@@ -1894,7 +1841,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
 
        ifo = ifp->options;
        state = D6_STATE(ifp);
-       TAILQ_FOREACH(ifd, ifaces, next) {
+       TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
                k = 0;
                carrier_warned = 0;
                TAILQ_FOREACH(ap, &state->addrs, next) {
@@ -1961,7 +1908,8 @@ dhcp6_delegate_prefix(struct interface *ifp)
                        for (k = 0; k < i; j++)
                                if (strcmp(sla->ifname, ia->sla[j].ifname) == 0)
                                        break;
-                       if (j >= i && find_interface(sla->ifname) == NULL)
+                       if (j >= i &&
+                           find_interface(ifp->ctx, sla->ifname) == NULL)
                                syslog(LOG_ERR,
                                    "%s: interface does not exist"
                                    " for delegation",
@@ -1989,7 +1937,7 @@ dhcp6_find_delegates(struct interface *ifp)
        struct interface *ifd;
 
        k = 0;
-       TAILQ_FOREACH(ifd, ifaces, next) {
+       TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
                ifo = ifd->options;
                if (ifo->ia_type != D6_OPTION_IA_PD)
                        continue;
@@ -2029,21 +1977,23 @@ dhcp6_find_delegates(struct interface *ifp)
                state = D6_STATE(ifp);
                state->state = DH6S_DELEGATED;
                ipv6nd_probeaddrs(&state->addrs);
-               ipv6_buildroutes();
+               ipv6_buildroutes(ifp->ctx);
        }
        return k;
 }
 
 /* ARGSUSED */
 static void
-dhcp6_handledata(__unused void *arg)
+dhcp6_handledata(void *arg)
 {
+       struct dhcpcd_ctx *dhcpcd_ctx;
+       struct ipv6_ctx *ctx;
        ssize_t len;
        size_t i;
        struct cmsghdr *cm;
        struct in6_pktinfo pkt;
        struct interface *ifp;
-       const char *sfrom, *op;
+       const char *op;
        struct dhcp6_message *r;
        struct dhcp6_state *state;
        const struct dhcp6_option *o, *auth;
@@ -2054,22 +2004,25 @@ dhcp6_handledata(__unused void *arg)
        int error;
        uint32_t u32;
 
-       len = recvmsg(sock, &rcvhdr, 0);
+       dhcpcd_ctx = arg;
+       ctx = dhcpcd_ctx->ipv6;
+       len = recvmsg(ctx->dhcp_fd, &ctx->rcvhdr, 0);
        if (len == -1) {
                syslog(LOG_ERR, "recvmsg: %m");
                return;
        }
-       sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
-           ntopbuf, INET6_ADDRSTRLEN);
+       ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
+           ctx->ntopbuf, sizeof(ctx->ntopbuf));
        if ((size_t)len < sizeof(struct dhcp6_message)) {
-               syslog(LOG_ERR, "DHCPv6 RA packet too short from %s", sfrom);
+               syslog(LOG_ERR, "DHCPv6 RA packet too short from %s",
+                   ctx->sfrom);
                return;
        }
 
        pkt.ipi6_ifindex = 0;
-       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
+       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
             cm;
-            cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
+            cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
        {
                if (cm->cmsg_level != IPPROTO_IPV6)
                        continue;
@@ -2084,17 +2037,18 @@ dhcp6_handledata(__unused void *arg)
        if (pkt.ipi6_ifindex == 0) {
                syslog(LOG_ERR,
                    "DHCPv6 reply did not contain index from %s",
-                   sfrom);
+                   ctx->sfrom);
                return;
        }
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, dhcpcd_ctx->ifaces, next) {
                if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
                        break;
        }
        if (ifp == NULL) {
                syslog(LOG_DEBUG,
-                   "DHCPv6 reply for unexpected interface from %s", sfrom);
+                   "DHCPv6 reply for unexpected interface from %s",
+                   ctx->sfrom);
                return;
        }
        state = D6_STATE(ifp);
@@ -2109,7 +2063,7 @@ dhcp6_handledata(__unused void *arg)
            state->state == DH6S_INFORMED)
                return;
 
-       r = (struct dhcp6_message *)rcvhdr.msg_iov[0].iov_base;
+       r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
        if (r->type != DHCP6_RECONFIGURE &&
            (r->xid[0] != state->send->xid[0] ||
            r->xid[1] != state->send->xid[1] ||
@@ -2122,33 +2076,37 @@ dhcp6_handledata(__unused void *arg)
                    r->xid[0], r->xid[1], r->xid[2],
                    state->send->xid[0], state->send->xid[1],
                    state->send->xid[2],
-                   sfrom);
+                   ctx->sfrom);
                return;
        }
 
        if (dhcp6_getmoption(D6_OPTION_SERVERID, r, len) == NULL) {
                syslog(LOG_DEBUG, "%s: no DHCPv6 server ID from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
                return;
        }
 
        o = dhcp6_getmoption(D6_OPTION_CLIENTID, r, len);
-       if (o == NULL || ntohs(o->len) != duid_len ||
-           memcmp(D6_COPTION_DATA(o), duid, duid_len) != 0)
+       if (o == NULL || ntohs(o->len) != dhcpcd_ctx->duid_len ||
+           memcmp(D6_COPTION_DATA(o),
+           dhcpcd_ctx->duid, dhcpcd_ctx->duid_len) != 0)
        {
                syslog(LOG_DEBUG, "%s: incorrect client ID from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
                return;
        }
 
        ifo = ifp->options;
-       for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++) {
+       for (i = 0, opt = dhcpcd_ctx->dhcp6_opts;
+           i < dhcpcd_ctx->dhcp6_opts_len;
+           i++, opt++)
+       {
                if (has_option_mask(ifo->requiremask6, opt->option) &&
                    dhcp6_getmoption(opt->option, r, len) == NULL)
                {
                        syslog(LOG_WARNING,
                            "%s: reject DHCPv6 (no option %s) from %s",
-                           ifp->name, opt->var, sfrom);
+                           ifp->name, opt->var, ctx->sfrom);
                        return;
                }
        }
@@ -2162,19 +2120,19 @@ dhcp6_handledata(__unused void *arg)
                {
                        syslog(LOG_DEBUG, "dhcp_auth_validate: %m");
                        syslog(LOG_ERR, "%s: authentication failed from %s",
-                           ifp->name, sfrom);
+                           ifp->name, ctx->sfrom);
                        return;
                }
                syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
                    ifp->name, state->auth.token->secretid);
        } else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
                syslog(LOG_ERR, "%s: no authentication from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
                return;
        } else if (ifo->auth.options & DHCPCD_AUTH_SEND)
                syslog(LOG_WARNING,
                    "%s: no authentication from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
 
        op = dhcp6_get_op(r->type);
        switch(r->type) {
@@ -2201,7 +2159,7 @@ dhcp6_handledata(__unused void *arg)
                        if (error == 1)
                                goto recv;
                        if (error == -1 ||
-                           dhcp6_validatelease(ifp, r, len, sfrom) == -1) {
+                           dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1){
                                dhcp6_startdiscover(ifp);
                                return;
                        }
@@ -2216,7 +2174,7 @@ dhcp6_handledata(__unused void *arg)
                case DH6S_REQUEST: /* FALLTHROUGH */
                case DH6S_RENEW: /* FALLTHROUGH */
                case DH6S_REBIND:
-                       if (dhcp6_validatelease(ifp, r, len, sfrom) == -1) {
+                       if (dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1){
                                /* PD doesn't use CONFIRM, so REBIND could
                                 * throw up an invalid prefix if we
                                 * changed link */
@@ -2259,17 +2217,18 @@ dhcp6_handledata(__unused void *arg)
                                syslog(LOG_ERR, "%s: invalid INF_MAX_RT %d",
                                    ifp->name, u32);
                }
-               if (dhcp6_validatelease(ifp, r, len, sfrom) == -1)
+               if (dhcp6_validatelease(ifp, r, len, ctx->sfrom) == -1)
                        return;
                break;
        case DHCP6_RECONFIGURE:
                if (auth == NULL) {
                        syslog(LOG_ERR,
                            "%s: unauthenticated Force Renew from %s",
-                           ifp->name, sfrom);
+                           ifp->name, ctx->sfrom);
                        return;
                }
-               syslog(LOG_INFO, "%s: Force Renew from %s", ifp->name, sfrom);
+               syslog(LOG_INFO, "%s: Force Renew from %s",
+                   ifp->name, ctx->sfrom);
                o = dhcp6_getmoption(D6_OPTION_RECONF_MSG, r, len);
                if (o == NULL) {
                        syslog(LOG_ERR,
@@ -2291,7 +2250,8 @@ dhcp6_handledata(__unused void *arg)
                                    ifp->name);
                                return;
                        }
-                       eloop_timeout_delete(dhcp6_startrenew, ifp);
+                       eloop_timeout_delete(ifp->ctx->eloop,
+                           dhcp6_startrenew, ifp);
                        dhcp6_startrenew(ifp);
                        break;
                case DHCP6_INFORMATION_REQ:
@@ -2301,7 +2261,8 @@ dhcp6_handledata(__unused void *arg)
                                    ifp->name);
                                return;
                        }
-                       eloop_timeout_delete(dhcp6_sendinform, ifp);
+                       eloop_timeout_delete(ifp->ctx->eloop,
+                           dhcp6_sendinform, ifp);
                        dhcp6_startinform(ifp);
                        break;
                default:
@@ -2339,8 +2300,8 @@ dhcp6_handledata(__unused void *arg)
                        break;
                ap = TAILQ_FIRST(&state->addrs);
                syslog(LOG_INFO, "%s: ADV %s from %s",
-                   ifp->name, ap->saddr, sfrom);
-               if (options & DHCPCD_TEST)
+                   ifp->name, ap->saddr, ctx->sfrom);
+               if (ifp->ctx->options & DHCPCD_TEST)
                        break;
                dhcp6_startrequest(ifp);
                return;
@@ -2355,10 +2316,10 @@ recv:
                }
        }
        syslog(has_new ? LOG_INFO : LOG_DEBUG,
-           "%s: %s received from %s", ifp->name, op, sfrom);
+           "%s: %s received from %s", ifp->name, op, ctx->sfrom);
 
        state->reason = NULL;
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        switch(state->state) {
        case DH6S_INFORM:
                state->rebind = 0;
@@ -2409,7 +2370,7 @@ recv:
                state->recv_len = 0;
        }
 
-       if (options & DHCPCD_TEST)
+       if (ifp->ctx->options & DHCPCD_TEST)
                script_runreason(ifp, "TEST");
        else {
                if (state->state == DH6S_INFORM)
@@ -2417,14 +2378,14 @@ recv:
                else
                        state->state = DH6S_BOUND;
                if (state->renew && state->renew != ND6_INFINITE_LIFETIME)
-                       eloop_timeout_add_sec(state->renew,
+                       eloop_timeout_add_sec(ifp->ctx->eloop, state->renew,
                            state->state == DH6S_INFORMED ?
                            dhcp6_startinform : dhcp6_startrenew, ifp);
                if (state->rebind && state->rebind != ND6_INFINITE_LIFETIME)
-                       eloop_timeout_add_sec(state->rebind,
+                       eloop_timeout_add_sec(ifp->ctx->eloop, state->rebind,
                            dhcp6_startrebind, ifp);
                if (state->expire && state->expire != ND6_INFINITE_LIFETIME)
-                       eloop_timeout_add_sec(state->expire,
+                       eloop_timeout_add_sec(ifp->ctx->eloop, state->expire,
                            dhcp6_startexpire, ifp);
                if (ifp->options->ia_type == D6_OPTION_IA_PD)
                        dhcp6_delegate_prefix(ifp);
@@ -2438,7 +2399,7 @@ recv:
                            "%s: renew in %"PRIu32" seconds,"
                            " rebind in %"PRIu32" seconds",
                            ifp->name, state->renew, state->rebind);
-               ipv6_buildroutes();
+               ipv6_buildroutes(ifp->ctx);
                dhcp6_writelease(ifp);
 
                len = 1;
@@ -2456,30 +2417,28 @@ recv:
                }
                if (len) {
                        script_runreason(ifp, state->reason);
-                       daemonise();
+                       daemonise(ifp->ctx);
                } else
                        syslog(LOG_DEBUG,
                            "%s: waiting for DHCPv6 DAD to complete",
                            ifp->name);
        }
 
-       if (options & DHCPCD_TEST ||
+       if (ifp->ctx->options & DHCPCD_TEST ||
            (ifp->options->options & DHCPCD_INFORM &&
-           !(options & DHCPCD_MASTER)))
+           !(ifp->ctx->options & DHCPCD_MASTER)))
        {
-               eloop_exit(EXIT_SUCCESS);
+               eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
        }
 }
 
 static int
-dhcp6_open(void)
+dhcp6_open(struct dhcpcd_ctx *dctx)
 {
+       struct ipv6_ctx *ctx;
        struct sockaddr_in6 sa;
        int n;
 
-       if (sndbuf == NULL && dhcp6_init() == -1)
-               return -1;
-
        memset(&sa, 0, sizeof(sa));
        sa.sin6_family = AF_INET6;
        sa.sin6_port = htons(DHCP6_CLIENT_PORT);
@@ -2487,42 +2446,50 @@ dhcp6_open(void)
        sa.sin6_len = sizeof(sa);
 #endif
 
-       sock = socket(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+       ctx = dctx->ipv6;
+       ctx->dhcp_fd = socket(PF_INET6,
+           SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
            IPPROTO_UDP);
-       if (sock == -1)
+       if (ctx->dhcp_fd == -1)
                return -1;
 
        n = 1;
-       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+       if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_REUSEADDR,
            &n, sizeof(n)) == -1)
                goto errexit;
 
        n = 1;
-       if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
+       if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_BROADCAST,
            &n, sizeof(n)) == -1)
                goto errexit;
 
 #ifdef SO_REUSEPORT
        n = 1;
-       if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
+       if (setsockopt(ctx->dhcp_fd, SOL_SOCKET, SO_REUSEPORT,
            &n, sizeof(n)) == -1)
                goto errexit;
 #endif
 
-       if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == -1)
+       if (bind(ctx->dhcp_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
                goto errexit;
 
        n = 1;
-       if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+       if (setsockopt(ctx->dhcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
            &n, sizeof(n)) == -1)
                goto errexit;
 
-       eloop_event_add(sock, dhcp6_handledata, NULL);
+       n = 1;
+       if (setsockopt(ctx->dhcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+           &n, sizeof(n)) == -1)
+               goto errexit;
+
+       eloop_event_add(dctx->eloop, ctx->dhcp_fd, dhcp6_handledata, dctx);
 
        return 0;
 
 errexit:
-       close(sock);
+       close(ctx->dhcp_fd);
+       ctx->dhcp_fd = -1;
        return -1;
 }
 
@@ -2587,7 +2554,7 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state)
        if (!(ifp->options->options & DHCPCD_DHCP6))
                return 0;
 
-       if (sock == -1 && dhcp6_open() == -1)
+       if (ifp->ctx->ipv6->dhcp_fd == -1 && dhcp6_open(ifp->ctx) == -1)
                return -1;
 
        ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
@@ -2643,8 +2610,9 @@ static void
 dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
 {
        struct dhcp6_state *state;
+       struct dhcpcd_ctx *ctx;
 
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 
        /*
         * As the interface is going away from dhcpcd we need to
@@ -2695,24 +2663,19 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
 
        /* If we don't have any more DHCP6 enabled interfaces,
         * close the global socketo and release resources */
-       if (ifaces) {
-               TAILQ_FOREACH(ifp, ifaces, next) {
+       ctx = ifp->ctx;
+       if (ctx->ifaces) {
+               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                        if (D6_STATE(ifp))
                                break;
                }
        }
        if (ifp == NULL) {
-               if (sock != -1) {
-                       close(sock);
-                       eloop_event_delete(sock);
-                       sock = -1;
-               }
-               free(sndbuf);
-               free(rcvbuf);
-               free(status);
-               sndbuf = NULL;
-               rcvbuf = NULL;
-               status = NULL;
+               if (ctx->ipv6->dhcp_fd != -1) {
+                       close(ctx->ipv6->dhcp_fd);
+                       eloop_event_delete(ctx->eloop, ctx->ipv6->dhcp_fd);
+                       ctx->ipv6->dhcp_fd = -1;
+               }
        }
 }
 
@@ -2731,16 +2694,16 @@ dhcp6_free(struct interface *ifp)
 }
 
 void
-dhcp6_handleifa(int cmd, const char *ifname,
+dhcp6_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
     const struct in6_addr *addr, int flags)
 {
        struct interface *ifp;
        struct dhcp6_state *state;
 
-       if (ifaces == NULL)
+       if (ctx->ifaces == NULL)
                return;
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                state = D6_STATE(ifp);
                if (state == NULL || strcmp(ifp->name, ifname))
                        continue;
@@ -2762,20 +2725,26 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
        char *v, *val, *pfx;
        const struct ipv6_addr *ap;
        uint32_t en;
+       const struct dhcpcd_ctx *ctx;
 
        state = D6_CSTATE(ifp);
        n = 0;
        ifo = ifp->options;
+       ctx = ifp->ctx;
 
        /* Zero our indexes */
        if (env) {
-               for (i = 0, opt = dhcp6_opts; i < dhcp6_opts_len; i++, opt++)
+               for (i = 0, opt = ctx->dhcp6_opts;
+                   i < ctx->dhcp6_opts_len;
+                   i++, opt++)
                        dhcp_zero_index(opt);
                for (i = 0, opt = ifp->options->dhcp6_override;
                    i < ifp->options->dhcp6_override_len;
                    i++, opt++)
                        dhcp_zero_index(opt);
-               for (i = 0, opt = vivso; i < vivso_len; i++, opt++)
+               for (i = 0, opt = ctx->vivso;
+                   i < ctx->vivso_len;
+                   i++, opt++)
                        dhcp_zero_index(opt);
                i = strlen(prefix) + strlen("_dhcp6") + 1;
                pfx = malloc(i);
@@ -2817,21 +2786,23 @@ dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
                } else
                        vo = NULL;
                if (i == ifo->dhcp6_override_len) {
-                       for (i = 0, opt = dhcp6_opts;
-                           i < dhcp6_opts_len;
+                       for (i = 0, opt = ctx->dhcp6_opts;
+                           i < ctx->dhcp6_opts_len;
                            i++, opt++)
                                if (opt->option == oc)
                                        break;
-                       if (i == dhcp6_opts_len)
+                       if (i == ctx->dhcp6_opts_len)
                                opt = NULL;
                }
                if (opt) {
-                       n += dhcp_envoption(env == NULL ? NULL : &env[n],
+                       n += dhcp_envoption(ifp->ctx,
+                           env == NULL ? NULL : &env[n],
                            pfx, ifp->name,
                            opt, dhcp6_getoption, D6_COPTION_DATA(o), ol);
                }
                if (vo) {
-                       n += dhcp_envoption(env == NULL ? NULL : &env[n],
+                       n += dhcp_envoption(ifp->ctx,
+                           env == NULL ? NULL : &env[n],
                            pfx, ifp->name,
                            vo, dhcp6_getoption,
                            D6_COPTION_DATA(o) + sizeof(en),
diff --git a/dhcp6.h b/dhcp6.h
index 4b097adf24fb20ade2c21c961412fe9c548e2cb8..322ad0dd79fba9a8fac9a42bec0dbd83a62042e1 100644 (file)
--- a/dhcp6.h
+++ b/dhcp6.h
@@ -227,18 +227,16 @@ struct dhcp6_state {
     ((const uint8_t *)(o) + sizeof(struct dhcp6_option))
 
 #ifdef INET6
-extern struct dhcp_opt *dhcp6_opts;
-extern size_t dhcp6_opts_len;
-
-void dhcp6_printoptions(void);
-int dhcp6_addrexists(const struct ipv6_addr *);
+void dhcp6_printoptions(const struct dhcpcd_ctx *);
+int dhcp6_addrexists(struct dhcpcd_ctx *, const struct ipv6_addr *);
 int dhcp6_find_delegates(struct interface *);
 int dhcp6_start(struct interface *, enum DH6S);
 void dhcp6_reboot(struct interface *);
 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, int);
+void dhcp6_handleifa(struct dhcpcd_ctx *, int, const char *,
+    const struct in6_addr *addr, int);
 void dhcp6_drop(struct interface *, const char *);
 #else
 #define dhcp6_printoptions()
index 1fe57aeaf087bc37b7cf4d14c32783355dc72977..aedeb7535bbd88478185065d291c9a548701bde8 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -65,14 +65,6 @@ const char dhcpcd_copyright[] = "Copyright (c) 2006-2014 Roy Marples";
 #include "platform.h"
 #include "script.h"
 
-struct if_head *ifaces = NULL;
-struct if_options *if_options = NULL;
-int ifac = 0;
-char **ifav = NULL;
-int ifdc = 0;
-char **ifdv = NULL;
-
-sigset_t dhcpcd_sigset;
 const int handle_sigs[] = {
        SIGALRM,
        SIGHUP,
@@ -83,13 +75,8 @@ const int handle_sigs[] = {
        0
 };
 
-static int pidfd = -1;
-static char *cffile;
-static int linkfd = -1;
-static char **ifv;
-static int ifc;
-static char **margv;
-static int margc;
+/* Handling signals needs *some* context */
+static struct dhcpcd_ctx *dhcpcd_ctx;
 
 static pid_t
 read_pid(const char *pidfile)
@@ -131,72 +118,79 @@ printf("usage: "PACKAGE"\t[-46ABbDdEGgHJKkLnpqTVw]\n"
 }
 
 static void
-free_globals(void)
+free_globals(struct dhcpcd_ctx *ctx)
 {
        struct dhcp_opt *opt;
 
-       if (ifac) {
-               for (ifac--; ifac >= 0; ifac--)
-                       free(ifav[ifac]);
-               free(ifav);
-               ifav = NULL;
+       if (ctx->ifac) {
+               for (ctx->ifac--; ctx->ifac >= 0; ctx->ifac--)
+                       free(ctx->ifav[ctx->ifac]);
+               free(ctx->ifav);
+               ctx->ifav = NULL;
        }
-       if (ifdc) {
-               for (ifdc--; ifdc >= 0; ifdc--)
-                       free(ifdv[ifac]);
-               free(ifdv);
-               ifdv = NULL;
+       if (ctx->ifdc) {
+               for (ctx->ifdc--; ctx->ifdc >= 0; ctx->ifdc--)
+                       free(ctx->ifdv[ctx->ifac]);
+               free(ctx->ifdv);
+               ctx->ifdv = NULL;
        }
 
 #ifdef INET
-       if (dhcp_opts) {
-               for (opt = dhcp_opts; dhcp_opts_len > 0;
-                   opt++, dhcp_opts_len--)
+       if (ctx->dhcp_opts) {
+               for (opt = ctx->dhcp_opts;
+                   ctx->dhcp_opts_len > 0;
+                   opt++, ctx->dhcp_opts_len--)
                        free_dhcp_opt_embenc(opt);
-               free(dhcp_opts);
-               dhcp_opts = NULL;
+               free(ctx->dhcp_opts);
+               ctx->dhcp_opts = NULL;
        }
 #endif
 #ifdef INET6
-       if (dhcp6_opts) {
-               for (opt = dhcp6_opts; dhcp6_opts_len > 0;
-                   opt++, dhcp6_opts_len--)
+       if (ctx->dhcp6_opts) {
+               for (opt = ctx->dhcp6_opts;
+                   ctx->dhcp6_opts_len > 0;
+                   opt++, ctx->dhcp6_opts_len--)
                        free_dhcp_opt_embenc(opt);
-               free(dhcp6_opts);
-               dhcp6_opts = NULL;
+               free(ctx->dhcp6_opts);
+               ctx->dhcp6_opts = NULL;
        }
 #endif
-       if (vivso) {
-               for (opt = vivso; vivso_len > 0; opt++, vivso_len--)
+       if (ctx->vivso) {
+               for (opt = ctx->vivso;
+                   ctx->vivso_len > 0;
+                   opt++, ctx->vivso_len--)
                        free_dhcp_opt_embenc(opt);
-               free(vivso);
-               vivso = NULL;
+               free(ctx->vivso);
+               ctx->vivso = NULL;
        }
 }
 
-/* ARGSUSED */
 static void
-handle_exit_timeout(__unused void *arg)
+handle_exit_timeout(void *arg)
 {
+       struct dhcpcd_ctx *ctx;
        int timeout;
 
+       ctx = arg;
        syslog(LOG_ERR, "timed out");
-       if (!(options & DHCPCD_IPV4) || !(options & DHCPCD_TIMEOUT_IPV4LL)) {
-               if (options & DHCPCD_MASTER) {
+       if (!(ctx->options & DHCPCD_IPV4) ||
+           !(ctx->options & DHCPCD_TIMEOUT_IPV4LL))
+       {
+               if (ctx->options & DHCPCD_MASTER) {
                        /* We've timed out, so remove the waitip requirements.
                         * If the user doesn't like this they can always set
                         * an infinite timeout. */
-                       options &=
+                       ctx->options &=
                            ~(DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6);
-                       daemonise();
+                       daemonise(ctx);
                } else
-                       eloop_exit(EXIT_FAILURE);
+                       eloop_exit(ctx->eloop, EXIT_FAILURE);
                return;
        }
-       options &= ~DHCPCD_TIMEOUT_IPV4LL;
+       ctx->options &= ~DHCPCD_TIMEOUT_IPV4LL;
        timeout = (PROBE_NUM * PROBE_MAX) + (PROBE_WAIT * 2);
        syslog(LOG_WARNING, "allowing %d seconds for IPv4LL timeout", timeout);
-       eloop_timeout_add_sec(timeout, handle_exit_timeout, NULL);
+       eloop_timeout_add_sec(ctx->eloop, timeout, handle_exit_timeout, ctx);
 }
 
 static inline int
@@ -211,7 +205,7 @@ write_pid(int fd, pid_t pid)
 
 /* Returns the pid of the child, otherwise 0. */
 pid_t
-daemonise(void)
+daemonise(struct dhcpcd_ctx *ctx)
 {
 #ifdef THERE_IS_NO_FORK
        errno = ENOSYS;
@@ -221,25 +215,28 @@ daemonise(void)
        char buf = '\0';
        int sidpipe[2], fd;
 
-       if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED)) {
-               if (options & DHCPCD_WAITIP4 &&
-                   !ipv4_addrexists(NULL))
+       if (ctx->options & DHCPCD_DAEMONISE &&
+           !(ctx->options & DHCPCD_DAEMONISED))
+       {
+               if (ctx->options & DHCPCD_WAITIP4 &&
+                   !ipv4_addrexists(ctx, NULL))
                        return 0;
-               if (options & DHCPCD_WAITIP6 &&
-                   !ipv6nd_addrexists(NULL) &&
-                   !dhcp6_addrexists(NULL))
+               if (ctx->options & DHCPCD_WAITIP6 &&
+                   !ipv6nd_addrexists(ctx, NULL) &&
+                   !dhcp6_addrexists(ctx, NULL))
                        return 0;
-               if ((options &
+               if ((ctx->options &
                    (DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6)) ==
-                   DHCPCD_WAITIP &&
-                   !ipv4_addrexists(NULL) &&
-                   !ipv6nd_addrexists(NULL) &&
-                   !dhcp6_addrexists(NULL))
+                   (DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6) &&
+                   !ipv4_addrexists(ctx, NULL) &&
+                   !ipv6nd_addrexists(ctx, NULL) &&
+                   !dhcp6_addrexists(ctx, NULL))
                        return 0;
        }
 
-       eloop_timeout_delete(handle_exit_timeout, NULL);
-       if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
+       eloop_timeout_delete(ctx->eloop, handle_exit_timeout, ctx);
+       if (ctx->options & DHCPCD_DAEMONISED ||
+           !(ctx->options & DHCPCD_DAEMONISE))
                return 0;
        /* Setup a signal pipe so parent knows when to exit. */
        if (pipe(sidpipe) == -1) {
@@ -276,24 +273,24 @@ daemonise(void)
        /* Done with the fd now */
        if (pid != 0) {
                syslog(LOG_INFO, "forked to background, child pid %d", pid);
-               write_pid(pidfd, pid);
-               close(pidfd);
-               pidfd = -1;
-               options |= DHCPCD_FORKED;
-               eloop_exit(EXIT_SUCCESS);
+               write_pid(ctx->pid_fd, pid);
+               close(ctx->pid_fd);
+               ctx->pid_fd = -1;
+               ctx->options |= DHCPCD_FORKED;
+               eloop_exit(ctx->eloop, EXIT_SUCCESS);
                return pid;
        }
-       options |= DHCPCD_DAEMONISED;
+       ctx->options |= DHCPCD_DAEMONISED;
        return pid;
 #endif
 }
 
 struct interface *
-find_interface(const char *ifname)
+find_interface(struct dhcpcd_ctx *ctx, const char *ifname)
 {
        struct interface *ifp;
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                if (strcmp(ifp->name, ifname) == 0)
                        return ifp;
        }
@@ -303,21 +300,23 @@ find_interface(const char *ifname)
 static void
 stop_interface(struct interface *ifp)
 {
+       struct dhcpcd_ctx *ctx;
 
+       ctx = ifp->ctx;
        syslog(LOG_INFO, "%s: removing interface", ifp->name);
        ifp->options->options |= DHCPCD_STOPPING;
 
        // Remove the interface from our list
-       TAILQ_REMOVE(ifaces, ifp, next);
+       TAILQ_REMOVE(ifp->ctx->ifaces, ifp, next);
        dhcp6_drop(ifp, NULL);
        ipv6nd_drop(ifp);
        dhcp_drop(ifp, "STOP");
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ctx->eloop, NULL, ifp);
        if (ifp->options->options & DHCPCD_DEPARTED)
                script_runreason(ifp, "DEPARTED");
        free_interface(ifp);
-       if (!(options & (DHCPCD_MASTER | DHCPCD_TEST)))
-               eloop_exit(EXIT_FAILURE);
+       if (!(ctx->options & (DHCPCD_MASTER | DHCPCD_TEST)))
+               eloop_exit(ctx->eloop, EXIT_FAILURE);
 }
 
 static void
@@ -352,8 +351,9 @@ configure_interface1(struct interface *ifp)
 
        /* We want to disable kernel interface RA as early as possible. */
        if (ifo->options & DHCPCD_IPV6RS) {
-               ra_global = check_ipv6(NULL, options & DHCPCD_IPV6RA_OWN ? 1:0);
-               ra_iface = check_ipv6(ifp->name,
+               ra_global = check_ipv6(ifp->ctx, NULL,
+                   ifp->ctx->options & DHCPCD_IPV6RA_OWN ? 1 : 0);
+               ra_iface = check_ipv6(ifp->ctx, ifp->name,
                    ifp->options->options & DHCPCD_IPV6RA_OWN ? 1 : 0);
                if (ra_global == -1 || ra_iface == -1)
                        ifo->options &= ~DHCPCD_IPV6RS;
@@ -457,7 +457,7 @@ select_profile(struct interface *ifp, const char *profile)
        int ret;
 
        ret = 0;
-       ifo = read_config(cffile, ifp->name, ifp->ssid, profile);
+       ifo = read_config(ifp->ctx, ifp->name, ifp->ssid, profile);
        if (ifo == NULL) {
                syslog(LOG_DEBUG, "%s: no profile %s", ifp->name, profile);
                ret = -1;
@@ -483,16 +483,17 @@ configure_interface(struct interface *ifp, int argc, char **argv)
 {
 
        select_profile(ifp, NULL);
-       add_options(ifp->name, ifp->options, argc, argv);
+       add_options(ifp->ctx, ifp->name, ifp->options, argc, argv);
        configure_interface1(ifp);
 }
 
 void
-handle_carrier(int carrier, int flags, const char *ifname)
+handle_carrier(struct dhcpcd_ctx *ctx, int carrier, int flags,
+    const char *ifname)
 {
        struct interface *ifp;
 
-       ifp = find_interface(ifname);
+       ifp = find_interface(ctx, ifname);
        if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
                return;
 
@@ -526,11 +527,11 @@ handle_carrier(int carrier, int flags, const char *ifname)
                        /* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the
                         * hardware address changes so we have to go
                         * through the disovery process to work it out. */
-                       handle_interface(0, ifp->name);
+                       handle_interface(ctx, 0, ifp->name);
 #endif
                        if (ifp->wireless)
                                getifssid(ifp->name, ifp->ssid);
-                       configure_interface(ifp, margc, margv);
+                       configure_interface(ifp, ctx->argc, ctx->argv);
                        script_runreason(ifp, "CARRIER");
                        start_interface(ifp);
                }
@@ -543,7 +544,7 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
        struct interface *ifn;
        size_t i;
 
-       TAILQ_FOREACH(ifn, ifaces, next) {
+       TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
                if (ifn == ifp)
                        continue;
                if (memcmp(ifn->options->iaid, iaid,
@@ -570,8 +571,9 @@ start_interface(void *arg)
        struct if_options *ifo = ifp->options;
        int nolease;
        size_t i;
+       char buf[DUID_LEN * 3];
 
-       handle_carrier(LINK_UNKNOWN, 0, ifp->name);
+       handle_carrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
        if (ifp->carrier == LINK_DOWN) {
                syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
                return;
@@ -579,16 +581,18 @@ start_interface(void *arg)
 
        if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6)) {
                /* Report client DUID */
-               if (duid == NULL) {
+               if (ifp->ctx->duid == NULL) {
                        if (duid_init(ifp) == 0)
                                return;
                        syslog(LOG_INFO, "DUID %s",
-                           hwaddr_ntoa(duid, duid_len));
+                           hwaddr_ntoa(ifp->ctx->duid, ifp->ctx->duid_len,
+                           buf, sizeof(buf)));
                }
 
                /* Report IAIDs */
                syslog(LOG_INFO, "%s: IAID %s", ifp->name,
-                   hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid)));
+                   hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid),
+                   buf, sizeof(buf)));
                warn_iaid_conflict(ifp, ifo->iaid);
                for (i = 0; i < ifo->ia_len; i++) {
                        if (memcmp(ifo->iaid, ifo->ia[i].iaid,
@@ -596,7 +600,8 @@ start_interface(void *arg)
                        {
                                syslog(LOG_INFO, "%s: IAID %s", ifp->name,
                                    hwaddr_ntoa(ifo->ia[i].iaid,
-                                   sizeof(ifo->ia[i].iaid)));
+                                   sizeof(ifo->ia[i].iaid),
+                                   buf, sizeof(buf)));
                                warn_iaid_conflict(ifp, ifo->ia[i].iaid);
                        }
                }
@@ -636,12 +641,13 @@ start_interface(void *arg)
                dhcp_start(ifp);
 }
 
-/* ARGSUSED */
 static void
-handle_link(__unused void *arg)
+handle_link(void *arg)
 {
+       struct dhcpcd_ctx *ctx;
 
-       if (manage_link(linkfd) == -1 && errno != ENXIO && errno != ENODEV)
+       ctx = arg;
+       if (manage_link(ctx) == -1 && errno != ENXIO && errno != ENODEV)
                syslog(LOG_ERR, "manage_link: %m");
 }
 
@@ -654,16 +660,16 @@ init_state(struct interface *ifp, int argc, char **argv)
        configure_interface(ifp, argc, argv);
        ifo = ifp->options;
 
-       if (ifo->options & DHCPCD_IPV4 && ipv4_init() == -1) {
+       if (ifo->options & DHCPCD_IPV4 && ipv4_init(ifp->ctx) == -1) {
                syslog(LOG_ERR, "ipv4_init: %m");
                ifo->options &= ~DHCPCD_IPV4;
        }
-       if (ifo->options & DHCPCD_IPV6 && ipv6_init() == -1) {
+       if (ifo->options & DHCPCD_IPV6 && ipv6_init(ifp->ctx) == NULL) {
                syslog(LOG_ERR, "ipv6_init: %m");
                ifo->options &= ~DHCPCD_IPV6RS;
        }
 
-       if (!(options & DHCPCD_TEST))
+       if (!(ifp->ctx->options & DHCPCD_TEST))
                script_runreason(ifp, "PREINIT");
 
        if (ifo->options & DHCPCD_LINK) {
@@ -680,22 +686,24 @@ init_state(struct interface *ifp, int argc, char **argv)
                        ifp->carrier = LINK_UNKNOWN;
                        return;
                }
-               if (reason && !(options & DHCPCD_TEST))
+               if (reason && !(ifp->ctx->options & DHCPCD_TEST))
                        script_runreason(ifp, reason);
        } else
                ifp->carrier = LINK_UNKNOWN;
 }
 
 void
-handle_interface(int action, const char *ifname)
+handle_interface(void *arg, int action, const char *ifname)
 {
+       struct dhcpcd_ctx *ctx;
        struct if_head *ifs;
        struct interface *ifp, *ifn, *ifl = NULL;
        const char * const argv[] = { ifname };
        int i;
 
+       ctx = arg;
        if (action == -1) {
-               ifp = find_interface(ifname);
+               ifp = find_interface(ctx, ifname);
                if (ifp != NULL) {
                        ifp->options->options |= DHCPCD_DEPARTED;
                        stop_interface(ifp);
@@ -704,20 +712,20 @@ handle_interface(int action, const char *ifname)
        }
 
        /* If running off an interface list, check it's in it. */
-       if (ifc) {
-               for (i = 0; i < ifc; i++)
-                       if (strcmp(ifv[i], ifname) == 0)
+       if (ctx->ifc) {
+               for (i = 0; i < ctx->ifc; i++)
+                       if (strcmp(ctx->ifv[i], ifname) == 0)
                                break;
-               if (i >= ifc)
+               if (i >= ctx->ifc)
                        return;
        }
 
-       ifs = discover_interfaces(-1, UNCONST(argv));
+       ifs = discover_interfaces(ctx, -1, UNCONST(argv));
        TAILQ_FOREACH_SAFE(ifp, ifs, next, ifn) {
                if (strcmp(ifp->name, ifname) != 0)
                        continue;
                /* Check if we already have the interface */
-               ifl = find_interface(ifp->name);
+               ifl = find_interface(ctx, ifp->name);
                if (ifl) {
                        /* The flags and hwaddr could have changed */
                        ifl->flags = ifp->flags;
@@ -726,10 +734,10 @@ handle_interface(int action, const char *ifname)
                                memcpy(ifl->hwaddr, ifp->hwaddr, ifl->hwlen);
                } else {
                        TAILQ_REMOVE(ifs, ifp, next);
-                       TAILQ_INSERT_TAIL(ifaces, ifp, next);
+                       TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
                }
                if (action == 1) {
-                       init_state(ifp, margc, margv);
+                       init_state(ifp, ctx->argc, ctx->argv);
                        start_interface(ifp);
                }
        }
@@ -743,11 +751,13 @@ handle_interface(int action, const char *ifname)
 }
 
 void
-handle_hwaddr(const char *ifname, const uint8_t *hwaddr, size_t hwlen)
+handle_hwaddr(struct dhcpcd_ctx *ctx, const char *ifname,
+    const uint8_t *hwaddr, size_t hwlen)
 {
        struct interface *ifp;
+       char buf[hwlen * 3];
 
-       ifp = find_interface(ifname);
+       ifp = find_interface(ctx, ifname);
        if (ifp == NULL)
                return;
 
@@ -761,7 +771,7 @@ handle_hwaddr(const char *ifname, const uint8_t *hwaddr, size_t hwlen)
                return;
 
        syslog(LOG_INFO, "%s: new hardware address: %s", ifp->name,
-           hwaddr_ntoa(hwaddr, hwlen));
+           hwaddr_ntoa(hwaddr, hwlen, buf, sizeof(buf)));
        ifp->hwlen = hwlen;
        memcpy(ifp->hwaddr, hwaddr, hwlen);
 }
@@ -780,18 +790,18 @@ if_reboot(struct interface *ifp, int argc, char **argv)
 }
 
 static void
-reconf_reboot(int action, int argc, char **argv, int oi)
+reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
 {
        struct if_head *ifs;
        struct interface *ifn, *ifp;
 
-       ifs = discover_interfaces(argc - oi, argv + oi);
+       ifs = discover_interfaces(ctx, argc - oi, argv + oi);
        if (ifs == NULL)
                return;
 
        while ((ifp = TAILQ_FIRST(ifs))) {
                TAILQ_REMOVE(ifs, ifp, next);
-               ifn = find_interface(ifp->name);
+               ifn = find_interface(ctx, ifp->name);
                if (ifn) {
                        if (action)
                                if_reboot(ifn, argc, argv);
@@ -800,13 +810,13 @@ reconf_reboot(int action, int argc, char **argv, int oi)
                        free_interface(ifp);
                } else {
                        init_state(ifp, argc, argv);
-                       TAILQ_INSERT_TAIL(ifaces, ifp, next);
+                       TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
                        start_interface(ifp);
                }
        }
        free(ifs);
 
-       sort_interfaces();
+       sort_interfaces(ctx);
 }
 
 struct dhcpcd_siginfo {
@@ -817,11 +827,13 @@ struct dhcpcd_siginfo {
 static void
 handle_signal1(void *arg)
 {
+       struct dhcpcd_ctx *ctx;
        struct dhcpcd_siginfo *si;
        struct interface *ifp;
        struct if_options *ifo;
        int do_release;
 
+       ctx = dhcpcd_ctx;
        si = arg;
        do_release = 0;
        switch (si->signo) {
@@ -837,22 +849,17 @@ handle_signal1(void *arg)
                syslog(LOG_INFO, "received SIGALRM from PID %d, rebinding",
                    (int)si->pid);
 
-               free_globals();
-               ifav = NULL;
-               ifac = 0;
-               ifdc = 0;
-               ifdv = NULL;
-
-               ifo = read_config(cffile, NULL, NULL, NULL);
-               add_options(NULL, ifo, margc, margv);
+               free_globals(ctx);
+               ifo = read_config(ctx, NULL, NULL, NULL);
+               add_options(ctx, NULL, ifo, ctx->argc, ctx->argv);
                /* We need to preserve these two options. */
-               if (options & DHCPCD_MASTER)
+               if (ctx->options & DHCPCD_MASTER)
                    ifo->options |= DHCPCD_MASTER;
-               if (options & DHCPCD_DAEMONISED)
+               if (ctx->options & DHCPCD_DAEMONISED)
                    ifo->options |= DHCPCD_DAEMONISED;
-               options = ifo->options;
+               ctx->options = ifo->options;
                free_options(ifo);
-               reconf_reboot(1, ifc, ifv, 0);
+               reconf_reboot(ctx, 1, ctx->ifc, ctx->ifv, 0);
                return;
        case SIGHUP:
                syslog(LOG_INFO, "received SIGHUP from PID %d, releasing",
@@ -862,8 +869,8 @@ handle_signal1(void *arg)
        case SIGUSR1:
                syslog(LOG_INFO, "received SIGUSR from PID %d, reconfiguring",
                    (int)si->pid);
-               TAILQ_FOREACH(ifp, ifaces, next) {
-                   ipv4_applyaddr(ifp);
+               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+                       ipv4_applyaddr(ifp);
                }
                return;
        case SIGPIPE:
@@ -877,11 +884,11 @@ handle_signal1(void *arg)
                return;
        }
 
-       if (!(options & DHCPCD_TEST)) {
+       if (!(ctx->options & DHCPCD_TEST)) {
                /* drop_dhcp could change the order, so we do it like this. */
                for (;;) {
                        /* Be sane and drop the last config first */
-                       ifp = TAILQ_LAST(ifaces, if_head);
+                       ifp = TAILQ_LAST(ctx->ifaces, if_head);
                        if (ifp == NULL)
                                break;
                        if (do_release) {
@@ -892,7 +899,7 @@ handle_signal1(void *arg)
                        stop_interface(ifp);
                }
        }
-       eloop_exit(EXIT_FAILURE);
+       eloop_exit(ctx->eloop, EXIT_FAILURE);
 }
 
 static void
@@ -904,11 +911,12 @@ handle_signal(__unused int sig, siginfo_t *siginfo, __unused void *context)
         * as the very first thing to do. */
        dhcpcd_siginfo.signo = siginfo->si_signo;
        dhcpcd_siginfo.pid = siginfo->si_pid;
-       eloop_timeout_add_now(handle_signal1, &dhcpcd_siginfo);
+       eloop_timeout_add_now(dhcpcd_ctx->eloop,
+           handle_signal1, &dhcpcd_siginfo);
 }
 
 int
-handle_args(struct fd_list *fd, int argc, char **argv)
+handle_args(struct dhcpcd_ctx *ctx, struct fd_list *fd, int argc, char **argv)
 {
        struct interface *ifp;
        int do_exit = 0, do_release = 0, do_reboot = 0;
@@ -932,10 +940,10 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                        }
                        return 0;
                } else if (strcmp(*argv, "--getconfigfile") == 0) {
-                       len = strlen(cffile ? cffile : CONFIG) + 1;
+                       len = strlen(ctx->cffile) + 1;
                        iov[0].iov_base = &len;
                        iov[0].iov_len = sizeof(ssize_t);
-                       iov[1].iov_base = cffile ? cffile : UNCONST(CONFIG);
+                       iov[1].iov_base = UNCONST(ctx->cffile);
                        iov[1].iov_len = len;
                        if (writev(fd->fd, iov, 2) == -1) {
                                syslog(LOG_ERR, "writev: %m");
@@ -945,7 +953,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                } else if (strcmp(*argv, "--getinterfaces") == 0) {
                        len = 0;
                        if (argc == 1) {
-                               TAILQ_FOREACH(ifp, ifaces, next) {
+                               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                                        len++;
                                        if (D6_STATE_RUNNING(ifp))
                                                len++;
@@ -955,14 +963,14 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                                len = write(fd->fd, &len, sizeof(len));
                                if (len != sizeof(len))
                                        return -1;
-                               TAILQ_FOREACH(ifp, ifaces, next) {
+                               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                                        send_interface(fd->fd, ifp);
                                }
                                return 0;
                        }
                        opt = 0;
                        while (argv[++opt] != NULL) {
-                               TAILQ_FOREACH(ifp, ifaces, next) {
+                               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                                        if (strcmp(argv[opt], ifp->name) == 0) {
                                                len++;
                                                if (D6_STATE_RUNNING(ifp))
@@ -977,7 +985,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                                return -1;
                        opt = 0;
                        while (argv[++opt] != NULL) {
-                               TAILQ_FOREACH(ifp, ifaces, next) {
+                               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                                        if (strcmp(argv[opt], ifp->name) == 0)
                                                send_interface(fd->fd, ifp);
                                }
@@ -1035,7 +1043,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
 
        if (do_release || do_exit) {
                for (oi = optind; oi < argc; oi++) {
-                       if ((ifp = find_interface(argv[oi])) == NULL)
+                       if ((ifp = find_interface(ctx, argv[oi])) == NULL)
                                continue;
                        if (do_release) {
                                ifp->options->options |= DHCPCD_RELEASE;
@@ -1047,7 +1055,7 @@ handle_args(struct fd_list *fd, int argc, char **argv)
                return 0;
        }
 
-       reconf_reboot(do_reboot, argc, argv, optind);
+       reconf_reboot(ctx, do_reboot, argc, argv, optind);
        return 0;
 }
 
@@ -1077,16 +1085,18 @@ signal_init(void (*func)(int, siginfo_t *, void *), sigset_t *oldset)
 int
 main(int argc, char **argv)
 {
+       struct dhcpcd_ctx ctx;
        char *pidfile;
+       struct if_options *ifo;
        struct interface *ifp;
        uint16_t family = 0;
        int opt, oi = 0, sig = 0, i;
        size_t len;
        pid_t pid;
        struct timespec ts;
-       struct control_ctx control_ctx;
 
-       pidfile = NULL;
+       memset(&ctx, 0, sizeof(ctx));
+       dhcpcd_ctx = &ctx; /* for our signal handler */
        closefrom(3);
        openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
        setlogmask(LOG_UPTO(LOG_INFO));
@@ -1102,7 +1112,14 @@ main(int argc, char **argv)
                }
        }
 
-       control_ctx.fd = -1;
+       pidfile = NULL;
+       ifo = NULL;
+       ctx.cffile = CONFIG;
+       ctx.pid_fd = -1;
+       ctx.control_fd = -1;
+       ctx.dev_fd = -1;
+       ctx.link_fd = -1;
+       ctx.udp_fd = -1;
        i = 0;
        while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
        {
@@ -1114,7 +1131,7 @@ main(int argc, char **argv)
                        family = AF_INET6;
                        break;
                case 'f':
-                       cffile = optarg;
+                       ctx.cffile = optarg;
                        break;
                case 'g':
                        sig = SIGUSR1;
@@ -1143,10 +1160,10 @@ main(int argc, char **argv)
                }
        }
 
-       margv = argv;
-       margc = argc;
-       if_options = read_config(cffile, NULL, NULL, NULL);
-       opt = add_options(NULL, if_options, argc, argv);
+       ctx.argv = argv;
+       ctx.argc = argc;
+       ifo = read_config(&ctx, NULL, NULL, NULL);
+       opt = add_options(&ctx, NULL, ifo, argc, argv);
        if (opt != 1) {
                if (opt == 0)
                        usage();
@@ -1158,34 +1175,34 @@ main(int argc, char **argv)
 #ifdef INET
                if (family == 0 || family == AF_INET) {
                        printf("\nDHCPv4 options:\n");
-                       dhcp_printoptions();
+                       dhcp_printoptions(&ctx);
                }
 #endif
 #ifdef INET6
                if (family == 0 || family == AF_INET6) {
                        printf("\nDHCPv6 options:\n");
-                       dhcp6_printoptions();
+                       dhcp6_printoptions(&ctx);
                }
 #endif
                goto exit_success;
        }
-       options = if_options->options;
+       ctx.options = ifo->options;
        if (i != 0) {
                if (i == 1)
-                       options |= DHCPCD_TEST;
+                       ctx.options |= DHCPCD_TEST;
                else
-                       options |= DHCPCD_DUMPLEASE;
-               options |= DHCPCD_PERSISTENT;
-               options &= ~DHCPCD_DAEMONISE;
+                       ctx.options |= DHCPCD_DUMPLEASE;
+               ctx.options |= DHCPCD_PERSISTENT;
+               ctx.options &= ~DHCPCD_DAEMONISE;
        }
 
 #ifdef THERE_IS_NO_FORK
-       options &= ~DHCPCD_DAEMONISE;
+       ctx.options &= ~DHCPCD_DAEMONISE;
 #endif
 
-       if (options & DHCPCD_DEBUG)
+       if (ctx.options & DHCPCD_DEBUG)
                setlogmask(LOG_UPTO(LOG_DEBUG));
-       if (options & DHCPCD_QUIET) {
+       if (ctx.options & DHCPCD_QUIET) {
                i = open(_PATH_DEVNULL, O_RDWR);
                if (i == -1)
                        syslog(LOG_ERR, "%s: open: %m", __func__);
@@ -1195,7 +1212,7 @@ main(int argc, char **argv)
                }
        }
 
-       if (!(options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
+       if (!(ctx.options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
                /* If we have any other args, we should run as a single dhcpcd
                 *  instance for that interface. */
                len = strlen(PIDFILE) + IF_NAMESIZE + 2;
@@ -1208,14 +1225,14 @@ main(int argc, char **argv)
                        snprintf(pidfile, len, PIDFILE, "-", argv[optind]);
                else {
                        snprintf(pidfile, len, PIDFILE, "", "");
-                       options |= DHCPCD_MASTER;
+                       ctx.options |= DHCPCD_MASTER;
                }
        }
 
        if (chdir("/") == -1)
                syslog(LOG_ERR, "chdir `/': %m");
 
-       if (options & DHCPCD_DUMPLEASE) {
+       if (ctx.options & DHCPCD_DUMPLEASE) {
                if (optind != argc - 1) {
                        syslog(LOG_ERR, "dumplease requires an interface");
                        goto exit_failure;
@@ -1225,11 +1242,11 @@ main(int argc, char **argv)
                goto exit_success;
        }
 
-       if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) {
-               if ((i = control_open(&control_ctx)) != -1) {
+       if (!(ctx.options & (DHCPCD_MASTER | DHCPCD_TEST))) {
+               if ((i = control_open(&ctx)) != -1) {
                        syslog(LOG_INFO,
                            "sending commands to master dhcpcd process");
-                       len = control_send(&control_ctx, argc, argv);
+                       len = control_send(&ctx, argc, argv);
                        close(i);
                        if (len > 0) {
                                syslog(LOG_DEBUG, "send OK");
@@ -1280,7 +1297,7 @@ main(int argc, char **argv)
                }
        }
 
-       if (!(options & DHCPCD_TEST)) {
+       if (!(ctx.options & DHCPCD_TEST)) {
                if ((pid = read_pid(pidfile)) > 0 &&
                    kill(pid, 0) == 0)
                {
@@ -1296,35 +1313,40 @@ main(int argc, char **argv)
                if (mkdir(DBDIR, 0755) == -1 && errno != EEXIST)
                        syslog(LOG_ERR, "mkdir `%s': %m", DBDIR);
 
-               pidfd = open(pidfile,
+               ctx.pid_fd = open(pidfile,
                    O_WRONLY | O_CREAT | O_CLOEXEC | O_NONBLOCK,
                    0664);
-               if (pidfd == -1)
+               if (ctx.pid_fd == -1)
                        syslog(LOG_ERR, "open `%s': %m", pidfile);
                else {
                        /* Lock the file so that only one instance of dhcpcd
                         * runs on an interface */
-                       if (flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
+                       if (flock(ctx.pid_fd, LOCK_EX | LOCK_NB) == -1) {
                                syslog(LOG_ERR, "flock `%s': %m", pidfile);
-                               close(pidfd);
-                               pidfd = -1;
+                               close(ctx.pid_fd);
+                               ctx.pid_fd = -1;
                                goto exit_failure;
                        }
-                       write_pid(pidfd, getpid());
+                       write_pid(ctx.pid_fd, getpid());
                }
        }
 
        syslog(LOG_INFO, "version " VERSION " starting");
-       options |= DHCPCD_STARTED;
+       ctx.options |= DHCPCD_STARTED;
+       ctx.eloop = eloop_init();
+       if (ctx.eloop == NULL) {
+               syslog(LOG_ERR, "%s: %m", __func__);
+               goto exit_failure;
+       }
 
        /* Save signal mask, block and redirect signals to our handler */
-       if (signal_init(handle_signal, &dhcpcd_sigset) == -1) {
+       if (signal_init(handle_signal, &ctx.sigset) == -1) {
                syslog(LOG_ERR, "signal_setup: %m");
                goto exit_failure;
        }
 
-       if (options & DHCPCD_MASTER) {
-               if (control_start(&control_ctx) == -1)
+       if (ctx.options & DHCPCD_MASTER) {
+               if (control_start(&ctx) == -1)
                        syslog(LOG_ERR, "control_start: %m");
        }
 
@@ -1335,108 +1357,108 @@ main(int argc, char **argv)
        }
 #endif
 
-       ifc = argc - optind;
-       ifv = argv + optind;
+       ctx.ifc = argc - optind;
+       ctx.ifv = argv + optind;
 
        /* When running dhcpcd against a single interface, we need to retain
         * the old behaviour of waiting for an IP address */
-       if (ifc == 1 && !(options & DHCPCD_BACKGROUND))
-               options |= DHCPCD_WAITIP;
+       if (ctx.ifc == 1 && !(ctx.options & DHCPCD_BACKGROUND))
+               ctx.options |= DHCPCD_WAITIP;
 
        /* RTM_NEWADDR goes through the link socket as well which we
         * need for IPv6 DAD, so we check for DHCPCD_LINK in handle_carrier
         * instead.
         * We also need to open this before checking for interfaces below
         * so that we pickup any new addresses during the discover phase. */
-       if (linkfd == -1) {
-               linkfd = open_link_socket();
-               if (linkfd == -1)
-                       syslog(LOG_ERR, "open_link_socket: %m");
-               else
-                       eloop_event_add(linkfd, handle_link, NULL);
-       }
+       ctx.link_fd = open_link_socket();
+       if (ctx.link_fd == -1)
+               syslog(LOG_ERR, "open_link_socket: %m");
+       else
+               eloop_event_add(ctx.eloop, ctx.link_fd, handle_link, &ctx);
 
        /* Start any dev listening plugin which may want to
         * change the interface name provided by the kernel */
-       if ((options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
+       if ((ctx.options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
            (DHCPCD_MASTER | DHCPCD_DEV))
-               dev_start(dev_load);
+               dev_start(&ctx);
 
-       ifaces = discover_interfaces(ifc, ifv);
-       for (i = 0; i < ifc; i++) {
-               if (find_interface(ifv[i]) == NULL)
+       ctx.ifaces = discover_interfaces(&ctx, ctx.ifc, ctx.ifv);
+       for (i = 0; i < ctx.ifc; i++) {
+               if (find_interface(&ctx, ctx.ifv[i]) == NULL)
                        syslog(LOG_ERR, "%s: interface not found or invalid",
-                           ifv[i]);
+                           ctx.ifv[i]);
        }
-       if (ifaces == NULL || TAILQ_FIRST(ifaces) == NULL) {
-               if (ifc == 0)
+       if (ctx.ifaces == NULL || TAILQ_FIRST(ctx.ifaces) == NULL) {
+               if (ctx.ifc == 0)
                        syslog(LOG_ERR, "no valid interfaces found");
                else
                        goto exit_failure;
-               if (!(options & DHCPCD_LINK)) {
+               if (!(ctx.options & DHCPCD_LINK)) {
                        syslog(LOG_ERR,
                            "aborting as link detection is disabled");
                        goto exit_failure;
                }
        }
 
-       if (options & DHCPCD_BACKGROUND && daemonise())
+       if (ctx.options & DHCPCD_BACKGROUND && daemonise(&ctx))
                goto exit_success;
 
        opt = 0;
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx.ifaces, next) {
                init_state(ifp, argc, argv);
                if (ifp->carrier != LINK_DOWN)
                        opt = 1;
        }
 
-       if (!(options & DHCPCD_BACKGROUND)) {
+       if (!(ctx.options & DHCPCD_BACKGROUND)) {
                /* If we don't have a carrier, we may have to wait for a second
                 * before one becomes available if we brought an interface up */
                if (opt == 0 &&
-                   options & DHCPCD_LINK &&
-                   options & DHCPCD_WAITUP &&
-                   !(options & DHCPCD_WAITIP))
+                   ctx.options & DHCPCD_LINK &&
+                   ctx.options & DHCPCD_WAITUP &&
+                   !(ctx.options & DHCPCD_WAITIP))
                {
                        ts.tv_sec = 1;
                        ts.tv_nsec = 0;
                        nanosleep(&ts, NULL);
-                       TAILQ_FOREACH(ifp, ifaces, next) {
-                               handle_carrier(LINK_UNKNOWN, 0, ifp->name);
+                       TAILQ_FOREACH(ifp, ctx.ifaces, next) {
+                               handle_carrier(&ctx, LINK_UNKNOWN, 0,
+                                   ifp->name);
                                if (ifp->carrier != LINK_DOWN) {
                                        opt = 1;
                                        break;
                                }
                        }
                }
-               if (options & DHCPCD_MASTER)
-                       i = if_options->timeout;
-               else if ((ifp = TAILQ_FIRST(ifaces)))
+               if (ctx.options & DHCPCD_MASTER)
+                       i = ifo->timeout;
+               else if ((ifp = TAILQ_FIRST(ctx.ifaces)))
                        i = ifp->options->timeout;
                else
                        i = 0;
                if (opt == 0 &&
-                   options & DHCPCD_LINK &&
-                   !(options & DHCPCD_WAITIP))
+                   ctx.options & DHCPCD_LINK &&
+                   !(ctx.options & DHCPCD_WAITIP))
                {
                        syslog(LOG_WARNING, "no interfaces have a carrier");
-                       if (daemonise())
+                       if (daemonise(&ctx))
                                goto exit_success;
                } else if (i > 0) {
-                       if (options & DHCPCD_IPV4LL)
-                               options |= DHCPCD_TIMEOUT_IPV4LL;
-                       eloop_timeout_add_sec(i, handle_exit_timeout, NULL);
+                       if (ctx.options & DHCPCD_IPV4LL)
+                               ctx.options |= DHCPCD_TIMEOUT_IPV4LL;
+                       eloop_timeout_add_sec(ctx.eloop, i,
+                           handle_exit_timeout, &ctx);
                }
        }
-       free_options(if_options);
-       if_options = NULL;
+       free_options(ifo);
+       ifo = NULL;
 
-       sort_interfaces();
-       TAILQ_FOREACH(ifp, ifaces, next) {
-               eloop_timeout_add_sec(0, start_interface, ifp);
+       sort_interfaces(&ctx);
+       TAILQ_FOREACH(ifp, ctx.ifaces, next) {
+               eloop_timeout_add_sec(ctx.eloop, 0, start_interface, ifp);
        }
 
-       i = eloop_start(&dhcpcd_sigset);
+       i = eloop_start(ctx.eloop, &ctx.sigset);
        goto exit1;
 
 exit_success:
@@ -1447,51 +1469,36 @@ exit_failure:
        i = EXIT_FAILURE;
 
 exit1:
-       /* Free memory and close fd's.
-        * We also set global variables back to their initial variables
-        * so we work nicely in a threads based environment as opposed to
-        * the normal process one. */
-       if (ifaces) {
-               while ((ifp = TAILQ_FIRST(ifaces))) {
-                       TAILQ_REMOVE(ifaces, ifp, next);
+       /* Free memory and close fd's */
+       if (ctx.ifaces) {
+               while ((ifp = TAILQ_FIRST(ctx.ifaces))) {
+                       TAILQ_REMOVE(ctx.ifaces, ifp, next);
                        free_interface(ifp);
                }
-               free(ifaces);
-               ifaces = NULL;
-       }
-
-       if (duid) {
-               free(duid);
-               duid = NULL;
-       }
-       if (if_options) {
-               free_options(if_options);
-               if_options = NULL;
-       }
-       free_globals();
-       restore_kernel_ra();
-       ipv4_free(NULL);
-       ipv6_free(NULL);
-       dev_stop(options & DHCPCD_DAEMONISED);
-       if (linkfd != -1) {
-               close(linkfd);
-               linkfd = -1;
-       }
-       if (pidfd > -1) {
-               if (options & DHCPCD_MASTER) {
-                       if (control_stop(&control_ctx) == -1)
+               free(ctx.ifaces);
+       }
+       free(ctx.duid);
+       if (ctx.link_fd != -1)
+               close(ctx.link_fd);
+
+       free_options(ifo);
+       free_globals(&ctx);
+       restore_kernel_ra(&ctx);
+       ipv4_ctxfree(&ctx);
+       ipv6_ctxfree(&ctx);
+       dev_stop(&ctx, !(ctx.options & DHCPCD_FORKED));
+       if (ctx.pid_fd != -1) {
+               if (ctx.options & DHCPCD_MASTER) {
+                       if (control_stop(&ctx) == -1)
                                syslog(LOG_ERR, "control_stop: %m:");
                }
-               close(pidfd);
+               close(ctx.pid_fd);
                unlink(pidfile);
-               pidfd = -1;
-       }
-       if (pidfile) {
-               free(pidfile);
-               pidfile = NULL;
        }
+       free(pidfile);
+       eloop_free(ctx.eloop);
 
-       if (options & DHCPCD_STARTED && !(options & DHCPCD_FORKED))
+       if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
                syslog(LOG_INFO, "exited");
        return i;
 }
index bf90042ae4a757e380b2472f96bf9648c362ef98..dd326ddc10691cb2c2d2e303cf5d24ffdf74c831 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@
 #define IF_DATA_MAX    5
 
 struct interface {
+       struct dhcpcd_ctx *ctx;
        TAILQ_ENTRY(interface) next;
        char name[IF_NAMESIZE];
        unsigned int index;
@@ -67,23 +68,77 @@ struct interface {
        struct if_options *options;
        void *if_data[IF_DATA_MAX];
 };
-extern TAILQ_HEAD(if_head, interface) *ifaces;
+TAILQ_HEAD(if_head, interface);
 
-extern sigset_t dhcpcd_sigset;
-extern int ifac;
-extern char **ifav;
-extern int ifdc;
-extern char **ifdv;
-extern struct if_options *if_options;
+struct dhcpcd_ctx {
+       sigset_t sigset;
+       const char *cffile;
+       unsigned long long options;
+       int argc;
+       char **argv;
+       int ifac;       /* allowed interfaces */
+       char **ifav;    /* allowed interfaces */
+       int ifdc;       /* denied interfaces */
+       char **ifdv;    /* denied interfaces */
+       int ifc;        /* listed interfaces */
+       char **ifv;     /* listed interfaces */
+       unsigned char *duid;
+       size_t duid_len;
+       int pid_fd;
+       int link_fd;
+       struct if_head *ifaces;
+
+       struct eloop_ctx *eloop;
+
+       int control_fd;
+       struct fd_list *control_fds;
+
+       /* DHCP Enterprise options, RFC3925 */
+       struct dhcp_opt *vivso;
+       size_t vivso_len;
+
+#ifdef INET
+       struct dhcp_opt *dhcp_opts;
+       size_t dhcp_opts_len;
+       struct rt_head *ipv4_routes;
+
+       int udp_fd;
+       uint8_t *packet;
+
+       /* Our aggregate option buffer.
+        * We ONLY use this when options are split, which for most purposes is
+        * practically never. See RFC3396 for details. */
+       uint8_t *opt_buffer;
+#endif
+#ifdef INET6
+       struct dhcp_opt *dhcp6_opts;
+       size_t dhcp6_opts_len;
+       struct ipv6_ctx *ipv6;
+#ifdef __linux__
+       char **ra_restore;
+       ssize_t ra_restore_len;
+#endif /* __linux__ */
+#endif /* INET6 */
+
+#ifdef PLUGIN_DEV
+       char *dev_load;
+       int dev_fd;
+       struct dev *dev;
+       void *dev_handle;
+#endif
+
+
+};
 
 extern const int handle_sigs[];
 
-pid_t daemonise(void);
-struct interface *find_interface(const char *);
-int handle_args(struct fd_list *, int, char **);
-void handle_carrier(int, int, const char *);
-void handle_interface(int, const char *);
-void handle_hwaddr(const char *, const unsigned char *, size_t);
+pid_t daemonise(struct dhcpcd_ctx *);
+struct interface *find_interface(struct dhcpcd_ctx *, const char *);
+int handle_args(struct dhcpcd_ctx *, struct fd_list *, int, char **);
+void handle_carrier(struct dhcpcd_ctx *, int, int, const char *);
+void handle_interface(void *, int, const char *);
+void handle_hwaddr(struct dhcpcd_ctx *, const char *,
+    const unsigned char *, size_t);
 void drop_interface(struct interface *, const char *);
 int select_profile(struct interface *, const char *);
 
diff --git a/duid.c b/duid.c
index acf917bdafdef060278e160e9b23db4054ad9da3..7f5d3d6cd700cbddba8ad44ab4e3a880004821ba 100644 (file)
--- a/duid.c
+++ b/duid.c
@@ -51,9 +51,6 @@
 #include "duid.h"
 #include "net.h"
 
-unsigned char *duid = NULL;
-size_t duid_len = 0;
-
 static size_t
 duid_make(unsigned char *d, const struct interface *ifp, uint16_t type)
 {
@@ -90,7 +87,7 @@ duid_get(unsigned char *d, const struct interface *ifp)
        FILE *fp;
        int x = 0;
        size_t len = 0;
-       char line[DUID_STRLEN + 1];
+       char line[DUID_STRLEN];
        const struct interface *ifp2;
 
        /* If we already have a DUID then use it as it's never supposed
@@ -121,7 +118,7 @@ duid_get(unsigned char *d, const struct interface *ifp)
        if (ifp->family == ARPHRD_NETROM) {
                syslog(LOG_WARNING, "%s: is a NET/ROM psuedo interface",
                    ifp->name);
-               TAILQ_FOREACH(ifp2, ifaces, next) {
+               TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
                        if (ifp2->family != ARPHRD_NETROM)
                                break;
                }
@@ -142,7 +139,7 @@ duid_get(unsigned char *d, const struct interface *ifp)
                return duid_make(d, ifp, DUID_LL);
        }
        len = duid_make(d, ifp, DUID_LLT);
-       x = fprintf(fp, "%s\n", hwaddr_ntoa(d, len));
+       x = fprintf(fp, "%s\n", hwaddr_ntoa(d, len, line, sizeof(line)));
        fclose(fp);
        /* Failed to write the duid? scrub it, we cannot use it */
        if (x < 1) {
@@ -156,13 +153,13 @@ duid_get(unsigned char *d, const struct interface *ifp)
 size_t duid_init(const struct interface *ifp)
 {
 
-       if (duid == NULL) {
-               duid = malloc(DUID_LEN);
-               if (duid == NULL) {
+       if (ifp->ctx->duid == NULL) {
+               ifp->ctx->duid = malloc(DUID_LEN);
+               if (ifp->ctx->duid == NULL) {
                        syslog(LOG_ERR, "%s: %m", __func__);
                        return 0;
                }
-               duid_len = duid_get(duid, ifp);
+               ifp->ctx->duid_len = duid_get(ifp->ctx->duid, ifp);
        }
-       return duid_len;
+       return ifp->ctx->duid_len;
 }
diff --git a/duid.h b/duid.h
index 0c509f424246dab893ca25aca885f358a5ccaf6d..b2f5eed4a73ea09e8991030b847a3b0bc2743810 100644 (file)
--- a/duid.h
+++ b/duid.h
@@ -34,9 +34,6 @@
 #  define DUID_LEN     128 + 2
 #endif
 
-extern unsigned char *duid;
-extern size_t duid_len;
-
 size_t duid_init(const struct interface *);
 
 #endif
diff --git a/eloop.c b/eloop.c
index 3798a82cf1179be29d345777058cca170991f8e2..a653cb9c80e535a4000ce94c8f9d5fcd565aefce 100644 (file)
--- a/eloop.c
+++ b/eloop.c
 #include "dhcpcd.h"
 #include "eloop.h"
 
-static struct timeval now;
-
-struct event {
-       TAILQ_ENTRY(event) next;
-       int fd;
-       void (*callback)(void *);
-       void *arg;
-       struct pollfd *pollfd;
-};
-static size_t events_len;
-static TAILQ_HEAD (event_head, event) events = TAILQ_HEAD_INITIALIZER(events);
-static struct event_head free_events = TAILQ_HEAD_INITIALIZER(free_events);
-
-struct timeout {
-       TAILQ_ENTRY(timeout) next;
-       struct timeval when;
-       void (*callback)(void *);
-       void *arg;
-       int queue;
-};
-static TAILQ_HEAD (timeout_head, timeout) timeouts
-    = TAILQ_HEAD_INITIALIZER(timeouts);
-static struct timeout_head free_timeouts
-    = TAILQ_HEAD_INITIALIZER(free_timeouts);
-
-static void (*volatile timeout0)(void *);
-static void *volatile timeout0_arg;
-
-static struct pollfd *fds;
-static size_t fds_len;
-
-static int eloop_exitnow;
-static int eloop_exitcode;
-
 static void
-eloop_event_setup_fds(void)
+eloop_event_setup_fds(struct eloop_ctx *ctx)
 {
-       struct event *e;
+       struct eloop_event *e;
        size_t i;
 
        i = 0;
-       TAILQ_FOREACH(e, &events, next) {
-               fds[i].fd = e->fd;
-               fds[i].events = POLLIN;
-               fds[i].revents = 0;
-               e->pollfd = &fds[i];
+       TAILQ_FOREACH(e, &ctx->events, next) {
+               ctx->fds[i].fd = e->fd;
+               ctx->fds[i].events = POLLIN;
+               ctx->fds[i].revents = 0;
+               e->pollfd = &ctx->fds[i];
                i++;
        }
 }
 
 int
-eloop_event_add(int fd, void (*callback)(void *), void *arg)
+eloop_event_add(struct eloop_ctx *ctx,
+    int fd, void (*callback)(void *), void *arg)
 {
-       struct event *e;
+       struct eloop_event *e;
        struct pollfd *nfds;
 
        /* We should only have one callback monitoring the fd */
-       TAILQ_FOREACH(e, &events, next) {
+       TAILQ_FOREACH(e, &ctx->events, next) {
                if (e->fd == fd) {
                        e->callback = callback;
                        e->arg = arg;
@@ -109,8 +76,8 @@ eloop_event_add(int fd, void (*callback)(void *), void *arg)
        }
 
        /* Allocate a new event if no free ones already allocated */
-       if ((e = TAILQ_FIRST(&free_events))) {
-               TAILQ_REMOVE(&free_events, e, next);
+       if ((e = TAILQ_FIRST(&ctx->free_events))) {
+               TAILQ_REMOVE(&ctx->free_events, e, next);
        } else {
                e = malloc(sizeof(*e));
                if (e == NULL) {
@@ -120,19 +87,19 @@ eloop_event_add(int fd, void (*callback)(void *), void *arg)
        }
 
        /* Ensure we can actually listen to it */
-       events_len++;
-       if (events_len > fds_len) {
-               fds_len += 5;
-               nfds = malloc(sizeof(*fds) * (fds_len + 5));
+       ctx->events_len++;
+       if (ctx->events_len > ctx->fds_len) {
+               ctx->fds_len += 5;
+               nfds = malloc(sizeof(*ctx->fds) * (ctx->fds_len + 5));
                if (nfds == NULL) {
                        syslog(LOG_ERR, "%s: %m", __func__);
-                       events_len--;
-                       TAILQ_INSERT_TAIL(&free_events, e, next);
+                       ctx->events_len--;
+                       TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
                        return -1;
                }
-               fds_len += 5;
-               free(fds);
-               fds = nfds;
+               ctx->fds_len += 5;
+               free(ctx->fds);
+               ctx->fds = nfds;
        }
 
        /* Now populate the structure and add it to the list */
@@ -145,33 +112,34 @@ eloop_event_add(int fd, void (*callback)(void *), void *arg)
         * message (which is likely to be that the DHCP addresses are wrong)
         * we insert new events at the queue head as the link fd will be
         * the first event added. */
-       TAILQ_INSERT_HEAD(&events, e, next);
-       eloop_event_setup_fds();
+       TAILQ_INSERT_HEAD(&ctx->events, e, next);
+       eloop_event_setup_fds(ctx);
        return 0;
 }
 
 void
-eloop_event_delete(int fd)
+eloop_event_delete(struct eloop_ctx *ctx, int fd)
 {
-       struct event *e;
+       struct eloop_event *e;
 
-       TAILQ_FOREACH(e, &events, next) {
+       TAILQ_FOREACH(e, &ctx->events, next) {
                if (e->fd == fd) {
-                       TAILQ_REMOVE(&events, e, next);
-                       TAILQ_INSERT_TAIL(&free_events, e, next);
-                       events_len--;
-                       eloop_event_setup_fds();
+                       TAILQ_REMOVE(&ctx->events, e, next);
+                       TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
+                       ctx->events_len--;
+                       eloop_event_setup_fds(ctx);
                        break;
                }
        }
 }
 
 int
-eloop_q_timeout_add_tv(int queue,
+eloop_q_timeout_add_tv(struct eloop_ctx *ctx, int queue,
     const struct timeval *when, void (*callback)(void *), void *arg)
 {
+       struct timeval now;
        struct timeval w;
-       struct timeout *t, *tt = NULL;
+       struct eloop_timeout *t, *tt = NULL;
 
        get_monotonic(&now);
        timeradd(&now, when, &w);
@@ -182,17 +150,17 @@ eloop_q_timeout_add_tv(int queue,
        }
 
        /* Remove existing timeout if present */
-       TAILQ_FOREACH(t, &timeouts, next) {
+       TAILQ_FOREACH(t, &ctx->timeouts, next) {
                if (t->callback == callback && t->arg == arg) {
-                       TAILQ_REMOVE(&timeouts, t, next);
+                       TAILQ_REMOVE(&ctx->timeouts, t, next);
                        break;
                }
        }
 
        if (t == NULL) {
                /* No existing, so allocate or grab one from the free pool */
-               if ((t = TAILQ_FIRST(&free_timeouts))) {
-                       TAILQ_REMOVE(&free_timeouts, t, next);
+               if ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
+                       TAILQ_REMOVE(&ctx->free_timeouts, t, next);
                } else {
                        t = malloc(sizeof(*t));
                        if (t == NULL) {
@@ -210,38 +178,39 @@ eloop_q_timeout_add_tv(int queue,
 
        /* The timeout list should be in chronological order,
         * soonest first. */
-       TAILQ_FOREACH(tt, &timeouts, next) {
+       TAILQ_FOREACH(tt, &ctx->timeouts, next) {
                if (timercmp(&t->when, &tt->when, <)) {
                        TAILQ_INSERT_BEFORE(tt, t, next);
                        return 0;
                }
        }
-       TAILQ_INSERT_TAIL(&timeouts, t, next);
+       TAILQ_INSERT_TAIL(&ctx->timeouts, t, next);
        return 0;
 }
 
 int
-eloop_q_timeout_add_sec(int queue, time_t when,
+eloop_q_timeout_add_sec(struct eloop_ctx *ctx, int queue, time_t when,
     void (*callback)(void *), void *arg)
 {
        struct timeval tv;
 
        tv.tv_sec = when;
        tv.tv_usec = 0;
-       return eloop_q_timeout_add_tv(queue, &tv, callback, arg);
+       return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
 }
 
 int
-eloop_timeout_add_now(void (*callback)(void *), void *arg)
+eloop_timeout_add_now(struct eloop_ctx *ctx,
+    void (*callback)(void *), void *arg)
 {
 
-       if (timeout0 != NULL) {
+       if (ctx->timeout0 != NULL) {
                syslog(LOG_WARNING, "%s: timeout0 already set", __func__);
-               return eloop_q_timeout_add_sec(0, 0, callback, arg);
+               return eloop_q_timeout_add_sec(ctx, 0, 0, callback, arg);
        }
 
-       timeout0 = callback;
-       timeout0_arg = arg;
+       ctx->timeout0 = callback;
+       ctx->timeout0_arg = arg;
        return 0;
 }
 
@@ -249,14 +218,14 @@ eloop_timeout_add_now(void (*callback)(void *), void *arg)
  * callbacks given. Handy for deleting everything apart from the expire
  * timeout. */
 static void
-eloop_q_timeouts_delete_v(int queue, void *arg,
+eloop_q_timeouts_delete_v(struct eloop_ctx *ctx, int queue, void *arg,
     void (*callback)(void *), va_list v)
 {
-       struct timeout *t, *tt;
+       struct eloop_timeout *t, *tt;
        va_list va;
        void (*f)(void *);
 
-       TAILQ_FOREACH_SAFE(t, &timeouts, next, tt) {
+       TAILQ_FOREACH_SAFE(t, &ctx->timeouts, next, tt) {
                if ((queue == 0 || t->queue == queue) && t->arg == arg &&
                    t->callback != callback)
                {
@@ -267,74 +236,121 @@ eloop_q_timeouts_delete_v(int queue, void *arg,
                        }
                        va_end(va);
                        if (f == NULL) {
-                               TAILQ_REMOVE(&timeouts, t, next);
-                               TAILQ_INSERT_TAIL(&free_timeouts, t, next);
+                               TAILQ_REMOVE(&ctx->timeouts, t, next);
+                               TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
                        }
                }
        }
 }
 
 void
-eloop_q_timeouts_delete(int queue, void *arg, void (*callback)(void *), ...)
+eloop_q_timeouts_delete(struct eloop_ctx *ctx, int queue,
+    void *arg, void (*callback)(void *), ...)
 {
        va_list va;
 
        va_start(va, callback);
-       eloop_q_timeouts_delete_v(queue, arg, callback, va);
+       eloop_q_timeouts_delete_v(ctx, queue, arg, callback, va);
        va_end(va);
 }
 
 void
-eloop_q_timeout_delete(int queue, void (*callback)(void *), void *arg)
+eloop_q_timeout_delete(struct eloop_ctx *ctx, int queue,
+    void (*callback)(void *), void *arg)
 {
-       struct timeout *t, *tt;
+       struct eloop_timeout *t, *tt;
 
-       TAILQ_FOREACH_SAFE(t, &timeouts, next, tt) {
+       TAILQ_FOREACH_SAFE(t, &ctx->timeouts, next, tt) {
                if (t->queue == queue && t->arg == arg &&
                    (!callback || t->callback == callback))
                {
-                       TAILQ_REMOVE(&timeouts, t, next);
-                       TAILQ_INSERT_TAIL(&free_timeouts, t, next);
+                       TAILQ_REMOVE(&ctx->timeouts, t, next);
+                       TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
                }
        }
 }
 
 void
-eloop_exit(int code)
+eloop_exit(struct eloop_ctx *ctx, int code)
 {
 
-       eloop_exitcode = code;
-       eloop_exitnow = 1;
+       ctx->exitcode = code;
+       ctx->exitnow = 1;
+}
+
+struct eloop_ctx *
+eloop_init(void)
+{
+       struct eloop_ctx *ctx;
+
+       ctx = calloc(1, sizeof(*ctx));
+       if (ctx) {
+               TAILQ_INIT(&ctx->events);
+               TAILQ_INIT(&ctx->free_events);
+               TAILQ_INIT(&ctx->timeouts);
+               TAILQ_INIT(&ctx->free_timeouts);
+               ctx->exitcode = EXIT_FAILURE;
+       }
+       return ctx;
+}
+
+
+void eloop_free(struct eloop_ctx *ctx)
+{
+       struct eloop_event *e;
+       struct eloop_timeout *t;
+
+       if (ctx == NULL)
+               return;
+
+       while ((e = TAILQ_FIRST(&ctx->events))) {
+               TAILQ_REMOVE(&ctx->events, e, next);
+               free(e);
+       }
+       while ((e = TAILQ_FIRST(&ctx->free_events))) {
+               TAILQ_REMOVE(&ctx->free_events, e, next);
+               free(e);
+       }
+       while ((t = TAILQ_FIRST(&ctx->timeouts))) {
+               TAILQ_REMOVE(&ctx->timeouts, t, next);
+               free(t);
+       }
+       while ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
+               TAILQ_REMOVE(&ctx->free_timeouts, t, next);
+               free(t);
+       }
+       free(ctx->fds);
+       free(ctx);
 }
 
 int
-eloop_start(const sigset_t *sigmask)
+eloop_start(struct eloop_ctx *ctx, const sigset_t *sigmask)
 {
+       struct timeval now;
        int n;
-       struct event *e;
-       struct timeout *t;
+       struct eloop_event *e;
+       struct eloop_timeout *t;
        struct timeval tv;
        struct timespec ts, *tsp;
        void (*t0)(void *);
 
-       eloop_exitcode = EXIT_FAILURE;
        for (;;) {
-               if (eloop_exitnow)
+               if (ctx->exitnow)
                        break;
 
                /* Run all timeouts first */
-               if (timeout0) {
-                       t0 = timeout0;
-                       timeout0 = NULL;
-                       t0(timeout0_arg);
+               if (ctx->timeout0) {
+                       t0 = ctx->timeout0;
+                       ctx->timeout0 = NULL;
+                       t0(ctx->timeout0_arg);
                        continue;
                }
-               if ((t = TAILQ_FIRST(&timeouts))) {
+               if ((t = TAILQ_FIRST(&ctx->timeouts))) {
                        get_monotonic(&now);
                        if (timercmp(&now, &t->when, >)) {
-                               TAILQ_REMOVE(&timeouts, t, next);
+                               TAILQ_REMOVE(&ctx->timeouts, t, next);
                                t->callback(t->arg);
-                               TAILQ_INSERT_TAIL(&free_timeouts, t, next);
+                               TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
                                continue;
                        }
                        timersub(&t->when, &now, &tv);
@@ -344,12 +360,12 @@ eloop_start(const sigset_t *sigmask)
                        /* No timeouts, so wait forever */
                        tsp = NULL;
 
-               if (tsp == NULL && events_len == 0) {
+               if (tsp == NULL && ctx->events_len == 0) {
                        syslog(LOG_ERR, "nothing to do");
                        break;
                }
 
-               n = pollts(fds, events_len, tsp, sigmask);
+               n = pollts(ctx->fds, ctx->events_len, tsp, sigmask);
                if (n == -1) {
                        if (errno == EAGAIN || errno == EINTR)
                                continue;
@@ -359,7 +375,7 @@ eloop_start(const sigset_t *sigmask)
 
                /* Process any triggered events. */
                if (n > 0) {
-                       TAILQ_FOREACH(e, &events, next) {
+                       TAILQ_FOREACH(e, &ctx->events, next) {
                                if (e->pollfd->revents & (POLLIN | POLLHUP)) {
                                        e->callback(e->arg);
                                        /* We need to break here as the
@@ -371,25 +387,5 @@ eloop_start(const sigset_t *sigmask)
                }
        }
 
-       /* Release our malloced resources */
-       while ((e = TAILQ_FIRST(&events))) {
-               TAILQ_REMOVE(&events, e, next);
-               free(e);
-       }
-       while ((e = TAILQ_FIRST(&free_events))) {
-               TAILQ_REMOVE(&free_events, e, next);
-               free(e);
-       }
-       while ((t = TAILQ_FIRST(&timeouts))) {
-               TAILQ_REMOVE(&timeouts, t, next);
-               free(t);
-       }
-       while ((t = TAILQ_FIRST(&free_timeouts))) {
-               TAILQ_REMOVE(&free_timeouts, t, next);
-               free(t);
-       }
-       free(fds);
-       fds_len = 0;
-
-       return eloop_exitcode;
+       return ctx->exitcode;
 }
diff --git a/eloop.h b/eloop.h
index afb61727807410852711fd7dd9d3280f44f31381..45439cbb3c143eba94a0998ce9f300c568197211 100644 (file)
--- a/eloop.h
+++ b/eloop.h
  * To add a CONTINUE definition, simply do the opposite of EXIT_FAILURE. */
 #define ELOOP_CONTINUE -EXIT_FAILURE
 
-#define eloop_timeout_add_tv(a, b, c) \
-    eloop_q_timeout_add_tv(ELOOP_QUEUE, a, b, c)
-#define eloop_timeout_add_sec(a, b, c) \
-    eloop_q_timeout_add_sec(ELOOP_QUEUE, a, b, c)
-#define eloop_timeout_delete(a, b) \
-    eloop_q_timeout_delete(ELOOP_QUEUE, a, b)
-#define eloop_timeouts_delete(a, ...) \
-    eloop_q_timeouts_delete(ELOOP_QUEUE, a, __VA_ARGS__)
-
-int eloop_event_add(int, void (*)(void *), void *);
-void eloop_event_delete(int);
-int eloop_q_timeout_add_sec(int queue, time_t, void (*)(void *), void *);
-int eloop_q_timeout_add_tv(int queue, const struct timeval *, void (*)(void *),
-    void *);
-int eloop_timeout_add_now(void (*)(void *), void *);
-void eloop_q_timeout_delete(int, void (*)(void *), void *);
-void eloop_q_timeouts_delete(int, void *, void (*)(void *), ...);
-void eloop_init(void);
-void eloop_exit(int);
-int eloop_start(const sigset_t *);
+struct eloop_event {
+       TAILQ_ENTRY(eloop_event) next;
+       int fd;
+       void (*callback)(void *);
+       void *arg;
+       struct pollfd *pollfd;
+};
+
+struct eloop_timeout {
+       TAILQ_ENTRY(eloop_timeout) next;
+       struct timeval when;
+       void (*callback)(void *);
+       void *arg;
+       int queue;
+};
+
+struct eloop_ctx {
+       size_t events_len;
+       TAILQ_HEAD (event_head, eloop_event) events;
+       struct event_head free_events;
+
+       TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
+       struct timeout_head free_timeouts;
+
+       void (*timeout0)(void *);
+       void *timeout0_arg;
+
+       struct pollfd *fds;
+       size_t fds_len;
+
+       int exitnow;
+       int exitcode;
+};
+
+#define eloop_timeout_add_tv(a, b, c, d) \
+    eloop_q_timeout_add_tv(a, ELOOP_QUEUE, b, c, d)
+#define eloop_timeout_add_sec(a, b, c, d) \
+    eloop_q_timeout_add_sec(a, ELOOP_QUEUE, b, c, d)
+#define eloop_timeout_delete(a, b, c) \
+    eloop_q_timeout_delete(a, ELOOP_QUEUE, b, c)
+#define eloop_timeouts_delete(a, b, ...) \
+    eloop_q_timeouts_delete(a, ELOOP_QUEUE, b, __VA_ARGS__)
+
+int eloop_event_add(struct eloop_ctx *, int, void (*)(void *), void *);
+void eloop_event_delete(struct eloop_ctx *, int);
+int eloop_q_timeout_add_sec(struct eloop_ctx *, int queue,
+    time_t, void (*)(void *), void *);
+int eloop_q_timeout_add_tv(struct eloop_ctx *, int queue,
+    const struct timeval *, void (*)(void *), void *);
+int eloop_timeout_add_now(struct eloop_ctx *, void (*)(void *), void *);
+void eloop_q_timeout_delete(struct eloop_ctx *, int, void (*)(void *), void *);
+void eloop_q_timeouts_delete(struct eloop_ctx *, int, void *,
+    void (*)(void *), ...);
+struct eloop_ctx * eloop_init(void);
+void eloop_free(struct eloop_ctx *);
+void eloop_exit(struct eloop_ctx *, int);
+int eloop_start(struct eloop_ctx *, const sigset_t *);
 
 #endif
index adc7bf5922f0f0867176c5767ea8d87122fb4efc..3af7e95e5ff12a5612d3542caf196ac70f94cbdf 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -543,7 +543,7 @@ in6_addr_flags(const char *ifname, const struct in6_addr *addr)
 #endif
 
 int
-manage_link(int fd)
+manage_link(struct dhcpcd_ctx *ctx)
 {
        /* route and ifwatchd like a msg buf size of 2048 */
        char msg[2048], *p, *e, *cp, ifname[IF_NAMESIZE];
@@ -565,7 +565,7 @@ manage_link(int fd)
 #endif
 
        for (;;) {
-               bytes = read(fd, msg, sizeof(msg));
+               bytes = read(ctx->link_fd, msg, sizeof(msg));
                if (bytes == -1) {
                        if (errno == EAGAIN)
                                return 0;
@@ -585,10 +585,12 @@ manage_link(int fd)
                                ifan = (struct if_announcemsghdr *)(void *)p;
                                switch(ifan->ifan_what) {
                                case IFAN_ARRIVAL:
-                                       handle_interface(1, ifan->ifan_name);
+                                       handle_interface(ctx, 1,
+                                           ifan->ifan_name);
                                        break;
                                case IFAN_DEPARTURE:
-                                       handle_interface(-1, ifan->ifan_name);
+                                       handle_interface(ctx, -1,
+                                           ifan->ifan_name);
                                        break;
                                }
                                break;
@@ -616,7 +618,8 @@ manage_link(int fd)
                                        len = LINK_UNKNOWN;
                                        break;
                                }
-                               handle_carrier(len, ifm->ifm_flags, ifname);
+                               handle_carrier(ctx, len,
+                                   ifm->ifm_flags, ifname);
                                break;
                        case RTM_DELETE:
                                if (~rtm->rtm_addrs &
@@ -633,7 +636,7 @@ manage_link(int fd)
                                COPYOUT(rt.dest, rti_info[RTAX_DST]);
                                COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
                                COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
-                               ipv4_routedeleted(&rt);
+                               ipv4_routedeleted(ctx, &rt);
 #endif
                                break;
 #ifdef RTM_CHGADDR
@@ -659,7 +662,7 @@ manage_link(int fd)
 #endif
                                        memcpy(&sdl, rti_info[RTAX_IFA],
                                            rti_info[RTAX_IFA]->sa_len);
-                                       handle_hwaddr(ifname,
+                                       handle_hwaddr(ctx, ifname,
                                            (const unsigned char*)CLLADDR(&sdl),
                                            sdl.sdl_alen);
                                        break;
@@ -669,7 +672,7 @@ manage_link(int fd)
                                        COPYOUT(rt.dest, rti_info[RTAX_IFA]);
                                        COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
                                        COPYOUT(rt.gate, rti_info[RTAX_BRD]);
-                                       ipv4_handleifa(rtm->rtm_type,
+                                       ipv4_handleifa(ctx, rtm->rtm_type,
                                            NULL, ifname,
                                            &rt.dest, &rt.net, &rt.gate);
                                        break;
@@ -689,7 +692,7 @@ manage_link(int fd)
                                                        break;
                                        } else
                                                ifa_flags = 0;
-                                       ipv6_handleifa(rtm->rtm_type, NULL,
+                                       ipv6_handleifa(ctx, rtm->rtm_type, NULL,
                                            ifname, &ia6, ifa_flags);
                                        break;
 #endif
index da4e0ab09c2555cbcd8a7dcebdd02e0336ffdc9a..02e71e2835ed6efcf53cd9401af5e59bc54d1538 100644 (file)
@@ -150,8 +150,8 @@ open_link_socket(void)
 }
 
 static int
-get_netlink(int fd, int flags,
-    int (*callback)(struct nlmsghdr *))
+get_netlink(struct dhcpcd_ctx *ctx, int fd, int flags,
+    int (*callback)(struct dhcpcd_ctx *, struct nlmsghdr *))
 {
        char *buf = NULL, *nbuf;
        ssize_t buflen = 0, bytes;
@@ -211,7 +211,7 @@ get_netlink(int fd, int flags,
                     NLMSG_OK(nlm, (size_t)bytes);
                     nlm = NLMSG_NEXT(nlm, bytes))
                {
-                       r = callback(nlm);
+                       r = callback(ctx, nlm);
                        if (r != 0)
                                goto eexit;
                }
@@ -223,7 +223,7 @@ eexit:
 }
 
 static int
-err_netlink(struct nlmsghdr *nlm)
+err_netlink(__unused struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
 {
        struct nlmsgerr *err;
        int l;
@@ -255,7 +255,7 @@ get_max_pid_t()
 }
 
 static int
-link_route(struct nlmsghdr *nlm)
+link_route(struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
 {
        int len, idx, metric;
        struct rtattr *rta;
@@ -303,7 +303,7 @@ link_route(struct nlmsghdr *nlm)
                case RTA_OIF:
                        idx = *(int *)RTA_DATA(rta);
                        if (if_indextoname(idx, ifn))
-                               rt.iface = find_interface(ifn);
+                               rt.iface = find_interface(ctx, ifn);
                        break;
                case RTA_PRIORITY:
                        metric = *(int *)RTA_DATA(rta);
@@ -315,7 +315,7 @@ link_route(struct nlmsghdr *nlm)
                if (metric == rt.iface->metric) {
 #ifdef INET
                        inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
-                       ipv4_routedeleted(&rt);
+                       ipv4_routedeleted(ctx, &rt);
 #endif
                }
        }
@@ -323,7 +323,7 @@ link_route(struct nlmsghdr *nlm)
 }
 
 static int
-link_addr(struct nlmsghdr *nlm)
+link_addr(struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
 {
        int len;
        struct rtattr *rta;
@@ -348,7 +348,7 @@ link_addr(struct nlmsghdr *nlm)
        ifa = NLMSG_DATA(nlm);
        if (if_indextoname(ifa->ifa_index, ifn) == NULL)
                return -1;
-       iface = find_interface(ifn);
+       iface = find_interface(ctx, ifn);
        if (iface == NULL)
                return 1;
        rta = (struct rtattr *) IFA_RTA(ifa);
@@ -374,7 +374,8 @@ link_addr(struct nlmsghdr *nlm)
                        }
                        rta = RTA_NEXT(rta, len);
                }
-               ipv4_handleifa(nlm->nlmsg_type, NULL, ifn, &addr, &net, &dest);
+               ipv4_handleifa(ctx, nlm->nlmsg_type, NULL, ifn,
+                   &addr, &net, &dest);
                break;
 #endif
 #ifdef INET6
@@ -389,7 +390,7 @@ link_addr(struct nlmsghdr *nlm)
                        }
                        rta = RTA_NEXT(rta, len);
                }
-               ipv6_handleifa(nlm->nlmsg_type, NULL, ifn,
+               ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifn,
                    &addr6, ifa->ifa_flags);
                break;
 #endif
@@ -415,16 +416,16 @@ static short l2addr_len(unsigned short if_type)
 }
 
 static int
-handle_rename(unsigned int ifindex, const char *ifname)
+handle_rename(struct dhcpcd_ctx *ctx, unsigned int ifindex, const char *ifname)
 {
        struct interface *ifp;
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                if (ifp->index == ifindex && strcmp(ifp->name, ifname)) {
-                       handle_interface(-1, ifp->name);
+                       handle_interface(ctx, -1, ifp->name);
                        /* Let dev announce the interface for renaming */
-                       if (!dev_listening())
-                               handle_interface(1, ifname);
+                       if (!dev_listening(ctx))
+                               handle_interface(ctx, 1, ifname);
                        return 1;
                }
        }
@@ -432,7 +433,7 @@ handle_rename(unsigned int ifindex, const char *ifname)
 }
 
 static int
-link_netlink(struct nlmsghdr *nlm)
+link_netlink(struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
 {
        int len;
        struct rtattr *rta, *hwaddr;
@@ -440,10 +441,10 @@ link_netlink(struct nlmsghdr *nlm)
        char ifn[IF_NAMESIZE + 1];
        struct interface *ifp;
 
-       len = link_route(nlm);
+       len = link_route(ctx, nlm);
        if (len != 0)
                return len;
-       len = link_addr(nlm);
+       len = link_addr(ctx, nlm);
        if (len != 0)
                return len;
 
@@ -481,7 +482,7 @@ link_netlink(struct nlmsghdr *nlm)
        }
 
        if (nlm->nlmsg_type == RTM_DELLINK) {
-               handle_interface(-1, ifn);
+               handle_interface(ctx, -1, ifn);
                return 1;
        }
 
@@ -490,21 +491,21 @@ link_netlink(struct nlmsghdr *nlm)
         * To trigger a valid hardware address pickup we need to pretend
         * that that don't exist until they have one. */
        if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
-               handle_interface(-1, ifn);
+               handle_interface(ctx, -1, ifn);
                return 1;
        }
 
        /* Check for interface name change */
-       if (handle_rename(ifi->ifi_index, ifn))
+       if (handle_rename(ctx, ifi->ifi_index, ifn))
                    return 1;
 
        /* Check for a new interface */
-       ifp = find_interface(ifn);
+       ifp = find_interface(ctx, ifn);
        if (ifp == NULL) {
                /* If are listening to a dev manager, let that announce
                 * the interface rather than the kernel. */
-               if (dev_listening() < 1)
-                       handle_interface(1, ifn);
+               if (dev_listening(ctx) < 1)
+                       handle_interface(ctx, 1, ifn);
                return 1;
        }
 
@@ -512,23 +513,23 @@ link_netlink(struct nlmsghdr *nlm)
        if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
                len = l2addr_len(ifi->ifi_type);
                if (hwaddr->rta_len == RTA_LENGTH(len))
-                       handle_hwaddr(ifn, RTA_DATA(hwaddr), len);
+                       handle_hwaddr(ctx, ifn, RTA_DATA(hwaddr), len);
        }
 
-       handle_carrier(ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
+       handle_carrier(ctx, ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
            ifi->ifi_flags, ifn);
        return 1;
 }
 
 int
-manage_link(int fd)
+manage_link(struct dhcpcd_ctx *ctx)
 {
 
-       return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
+       return get_netlink(ctx, ctx->link_fd, MSG_DONTWAIT, &link_netlink);
 }
 
 static int
-send_netlink(struct nlmsghdr *hdr)
+send_netlink(struct dhcpcd_ctx *ctx, struct nlmsghdr *hdr)
 {
        int s, r;
        struct sockaddr_nl snl;
@@ -552,7 +553,7 @@ send_netlink(struct nlmsghdr *hdr)
        hdr->nlmsg_seq = ++seq;
 
        if (sendmsg(s, &msg, 0) != -1)
-               r = get_netlink(s, 0, &err_netlink);
+               r = get_netlink(ctx, s, 0, &err_netlink);
        else
                r = -1;
        close(s);
@@ -623,100 +624,94 @@ if_address(const struct interface *iface,
     const struct in_addr *address, const struct in_addr *netmask,
     const struct in_addr *broadcast, int action)
 {
-       struct nlma *nlm;
+       struct nlma nlm;
        int retval = 0;
 
-       nlm = calloc(1, sizeof(*nlm));
-       if (nlm == NULL)
-               return -1;
-       nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-       nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
+       memset(&nlm, 0, sizeof(nlm));
+       nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+       nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
        if (action >= 0) {
-               nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
-               nlm->hdr.nlmsg_type = RTM_NEWADDR;
+               nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+               nlm.hdr.nlmsg_type = RTM_NEWADDR;
        } else
-               nlm->hdr.nlmsg_type = RTM_DELADDR;
-       nlm->ifa.ifa_index = iface->index;
-       nlm->ifa.ifa_family = AF_INET;
-       nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
+               nlm.hdr.nlmsg_type = RTM_DELADDR;
+       nlm.ifa.ifa_index = iface->index;
+       nlm.ifa.ifa_family = AF_INET;
+       nlm.ifa.ifa_prefixlen = inet_ntocidr(*netmask);
        /* This creates the aliased interface */
-       add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
+       add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL,
            iface->name, strlen(iface->name) + 1);
-       add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
+       add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL,
            &address->s_addr, sizeof(address->s_addr));
        if (action >= 0 && broadcast)
-               add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
+               add_attr_l(&nlm.hdr, sizeof(nlm), IFA_BROADCAST,
                    &broadcast->s_addr, sizeof(broadcast->s_addr));
 
-       if (send_netlink(&nlm->hdr) == -1)
+       if (send_netlink(iface->ctx, &nlm.hdr) == -1)
                retval = -1;
-       free(nlm);
        return retval;
 }
 
 int
 if_route(const struct rt *rt, int action)
 {
-       struct nlmr *nlm;
+       struct nlmr nlm;
        int retval = 0;
        struct dhcp_state *state;
 
-       nlm = calloc(1, sizeof(*nlm));
-       if (nlm == NULL)
-               return -1;
-       nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-       nlm->hdr.nlmsg_type = RTM_NEWROUTE;
+       memset(&nlm, 0, sizeof(nlm));
+       nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       nlm.hdr.nlmsg_type = RTM_NEWROUTE;
        if (action == 0)
-               nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
+               nlm.hdr.nlmsg_flags = NLM_F_REPLACE;
        else if (action == 1)
-               nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
+               nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
        else
-               nlm->hdr.nlmsg_type = RTM_DELROUTE;
-       nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
-       nlm->rt.rtm_family = AF_INET;
-       nlm->rt.rtm_table = RT_TABLE_MAIN;
+               nlm.hdr.nlmsg_type = RTM_DELROUTE;
+       nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
+       nlm.rt.rtm_family = AF_INET;
+       nlm.rt.rtm_table = RT_TABLE_MAIN;
 
        state = D_STATE(rt->iface);
        if (action == -1 || action == -2)
-               nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
+               nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
        else {
-               nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+               nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
                /* We only change route metrics for kernel routes */
                if (rt->dest.s_addr ==
                    (state->addr.s_addr & state->net.s_addr) &&
                    rt->net.s_addr == state->net.s_addr)
-                       nlm->rt.rtm_protocol = RTPROT_KERNEL;
+                       nlm.rt.rtm_protocol = RTPROT_KERNEL;
                else
-                       nlm->rt.rtm_protocol = RTPROT_BOOT;
+                       nlm.rt.rtm_protocol = RTPROT_BOOT;
                if (rt->gate.s_addr == INADDR_ANY ||
                    (rt->gate.s_addr == rt->dest.s_addr &&
                        rt->net.s_addr == INADDR_BROADCAST))
-                       nlm->rt.rtm_scope = RT_SCOPE_LINK;
+                       nlm.rt.rtm_scope = RT_SCOPE_LINK;
                else
-                       nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
-               nlm->rt.rtm_type = RTN_UNICAST;
+                       nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE;
+               nlm.rt.rtm_type = RTN_UNICAST;
        }
 
-       nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
-       add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
+       nlm.rt.rtm_dst_len = inet_ntocidr(rt->net);
+       add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
            &rt->dest.s_addr, sizeof(rt->dest.s_addr));
-       if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
-               add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
+       if (nlm.rt.rtm_protocol == RTPROT_KERNEL) {
+               add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
                    &state->addr.s_addr, sizeof(state->addr.s_addr));
        }
        /* If destination == gateway then don't add the gateway */
        if (rt->dest.s_addr != rt->gate.s_addr ||
            rt->net.s_addr != INADDR_BROADCAST)
-               add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
+               add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
                    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
 
        if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
-               add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
-       add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
+               add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
+       add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
 
-       if (send_netlink(&nlm->hdr) == -1)
+       if (send_netlink(rt->iface->ctx, &nlm.hdr) == -1)
                retval = -1;
-       free(nlm);
        return retval;
 }
 #endif
@@ -725,40 +720,37 @@ if_route(const struct rt *rt, int action)
 int
 if_address6(const struct ipv6_addr *ap, int action)
 {
-       struct nlma *nlm;
+       struct nlma nlm;
        struct ifa_cacheinfo cinfo;
        int retval = 0;
 
-       nlm = calloc(1, sizeof(*nlm));
-       if (nlm == NULL)
-               return -1;
-       nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-       nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
+       memset(&nlm, 0, sizeof(nlm));
+       nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+       nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
        if (action >= 0) {
-               nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
-               nlm->hdr.nlmsg_type = RTM_NEWADDR;
+               nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+               nlm.hdr.nlmsg_type = RTM_NEWADDR;
        } else
-               nlm->hdr.nlmsg_type = RTM_DELADDR;
-       nlm->ifa.ifa_index = ap->iface->index;
-       nlm->ifa.ifa_family = AF_INET6;
-       nlm->ifa.ifa_prefixlen = ap->prefix_len;
+               nlm.hdr.nlmsg_type = RTM_DELADDR;
+       nlm.ifa.ifa_index = ap->iface->index;
+       nlm.ifa.ifa_family = AF_INET6;
+       nlm.ifa.ifa_prefixlen = ap->prefix_len;
        /* This creates the aliased interface */
-       add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
+       add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL,
            ap->iface->name, strlen(ap->iface->name) + 1);
-       add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
+       add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL,
            &ap->addr.s6_addr, sizeof(ap->addr.s6_addr));
 
        if (action >= 0) {
                memset(&cinfo, 0, sizeof(cinfo));
                cinfo.ifa_prefered = ap->prefix_pltime;
                cinfo.ifa_valid = ap->prefix_vltime;
-               add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_CACHEINFO,
+               add_attr_l(&nlm.hdr, sizeof(nlm), IFA_CACHEINFO,
                    &cinfo, sizeof(cinfo));
        }
 
-       if (send_netlink(&nlm->hdr) == -1)
+       if (send_netlink(ap->iface->ctx, &nlm.hdr) == -1)
                retval = -1;
-       free(nlm);
        return retval;
 }
 
@@ -785,66 +777,61 @@ rta_add_attr_32(struct rtattr *rta, unsigned int maxlen,
 int
 if_route6(const struct rt6 *rt, int action)
 {
-       struct nlmr *nlm;
+       struct nlmr nlm;
        char metricsbuf[32];
        struct rtattr *metrics = (void *)metricsbuf;
        int retval = 0;
 
-       nlm = calloc(1, sizeof(*nlm));
-       if (nlm == NULL)
-               return -1;
-       nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-       nlm->hdr.nlmsg_type = RTM_NEWROUTE;
-       nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
+       memset(&nlm, 0, sizeof(nlm));
+       nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       nlm.hdr.nlmsg_type = RTM_NEWROUTE;
+       nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
        if (action == 0)
-               nlm->hdr.nlmsg_flags |= NLM_F_REPLACE;
+               nlm.hdr.nlmsg_flags |= NLM_F_REPLACE;
        else if (action == 1)
-               nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+               nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
        else
-               nlm->hdr.nlmsg_type = RTM_DELROUTE;
-       nlm->rt.rtm_family = AF_INET6;
-       nlm->rt.rtm_table = RT_TABLE_MAIN;
+               nlm.hdr.nlmsg_type = RTM_DELROUTE;
+       nlm.rt.rtm_family = AF_INET6;
+       nlm.rt.rtm_table = RT_TABLE_MAIN;
 
        if (action == -1 || action == -2)
-               nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
+               nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
        else {
-               nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+               nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
                /* None interface subnet routes are static. */
                if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
-                       nlm->rt.rtm_protocol = RTPROT_KERNEL;
-                       nlm->rt.rtm_scope = RT_SCOPE_LINK;
+                       nlm.rt.rtm_protocol = RTPROT_KERNEL;
+                       nlm.rt.rtm_scope = RT_SCOPE_LINK;
                } else
-                       nlm->rt.rtm_protocol = RTPROT_BOOT;
-               nlm->rt.rtm_type = RTN_UNICAST;
+                       nlm.rt.rtm_protocol = RTPROT_BOOT;
+               nlm.rt.rtm_type = RTN_UNICAST;
        }
 
-       nlm->rt.rtm_dst_len = ipv6_prefixlen(&rt->net);
-       add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
+       nlm.rt.rtm_dst_len = ipv6_prefixlen(&rt->net);
+       add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
            &rt->dest.s6_addr, sizeof(rt->dest.s6_addr));
 
        /* If destination == gateway then don't add the gateway */
        if (!IN6_IS_ADDR_UNSPECIFIED(&rt->gate) &&
            !IN6_ARE_ADDR_EQUAL(&rt->dest, &rt->gate))
-               add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
+               add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
                    &rt->gate.s6_addr, sizeof(rt->gate.s6_addr));
 
-       add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, rt->iface->index);
-       add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
+       add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
+       add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
 
        if (rt->mtu) {
                metrics->rta_type = RTA_METRICS;
                metrics->rta_len = RTA_LENGTH(0);
                rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
-               add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_METRICS,
+               add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS,
                    RTA_DATA(metrics), RTA_PAYLOAD(metrics));
        }
 
-       if (send_netlink(&nlm->hdr) == -1)
+       if (send_netlink(rt->iface->ctx, &nlm.hdr) == -1)
                retval = -1;
-       free(nlm);
        return retval;
-       errno = ENOTSUP;
-       return -1;
 }
 
 int
index f6b32e978008797eb65ca78a54566c5d12341101..3a5b6c0f1b116c448129c81b9dde592738f3950f 100644 (file)
@@ -52,8 +52,6 @@
 #include "ipv4.h"
 #include "platform.h"
 
-unsigned long long options = 0;
-
 /* These options only make sense in the config file, so don't use any
    valid short options for them */
 #define O_BASE                 MAX('z', 'Z') + 1
@@ -87,8 +85,6 @@ unsigned long long options = 0;
 #define O_NODHCP               O_BASE + 28
 #define O_NODHCP6              O_BASE + 29
 
-char *dev_load;
-
 const struct option cf_options[] = {
        {"background",      no_argument,       NULL, 'b'},
        {"script",          required_argument, NULL, 'c'},
@@ -495,15 +491,16 @@ parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
 #endif
 
 static const char *
-set_option_space(const char *arg, const struct dhcp_opt **d, size_t *dl,
+set_option_space(struct dhcpcd_ctx *ctx,
+    const char *arg, const struct dhcp_opt **d, size_t *dl,
     struct if_options *ifo,
     uint8_t *request[], uint8_t *require[], uint8_t *no[])
 {
 
 #ifdef INET6
        if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
-               *d = dhcp6_opts;
-               *dl = dhcp6_opts_len;
+               *d = ctx->dhcp6_opts;
+               *dl = ctx->dhcp6_opts_len;
                *request = ifo->requestmask6;
                *require = ifo->requiremask6;
                *no = ifo->nomask6;
@@ -512,8 +509,8 @@ set_option_space(const char *arg, const struct dhcp_opt **d, size_t *dl,
 #endif
 
 #ifdef INET
-       *d = dhcp_opts;
-       *dl = dhcp_opts_len;
+       *d = ctx->dhcp_opts;
+       *dl = ctx->dhcp_opts_len;
 #else
        *d = NULL;
        *dl = 0;
@@ -524,10 +521,6 @@ set_option_space(const char *arg, const struct dhcp_opt **d, size_t *dl,
        return arg;
 }
 
-/* Pointer to last defined option */
-static struct dhcp_opt *ldop;
-static struct dhcp_opt *edop;
-
 void
 free_dhcp_opt_embenc(struct dhcp_opt *opt)
 {
@@ -600,8 +593,8 @@ strend(const char *s)
 }
 
 static int
-parse_option(const char *ifname, struct if_options *ifo,
-    int opt, const char *arg)
+parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
+    int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop)
 {
        int i, l, t;
        unsigned int u;
@@ -703,7 +696,7 @@ parse_option(const char *ifname, struct if_options *ifo,
                }
                break;
        case 'o':
-               arg = set_option_space(arg, &d, &dl, ifo,
+               arg = set_option_space(ctx, arg, &d, &dl, ifo,
                    &request, &require, &no);
                if (make_option_mask(d, dl, request, arg, 1) != 0) {
                        syslog(LOG_ERR, "unknown option `%s'", arg);
@@ -838,7 +831,8 @@ parse_option(const char *ifname, struct if_options *ifo,
                }
                break;
        case 'z':
-               ifav = splitv(&ifac, ifav, arg);
+               if (ifname == NULL)
+                       ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg);
                break;
        case 'A':
                ifo->options &= ~DHCPCD_ARP;
@@ -917,7 +911,7 @@ parse_option(const char *ifname, struct if_options *ifo,
                ifo->options &= ~DHCPCD_IPV4LL;
                break;
        case 'O':
-               arg = set_option_space(arg, &d, &dl, ifo,
+               arg = set_option_space(ctx, arg, &d, &dl, ifo,
                    &request, &require, &no);
                if (make_option_mask(d, dl, request, arg, -1) != 0 ||
                    make_option_mask(d, dl, require, arg, -1) != 0 ||
@@ -928,7 +922,7 @@ parse_option(const char *ifname, struct if_options *ifo,
                }
                break;
        case 'Q':
-               arg = set_option_space(arg, &d, &dl, ifo,
+               arg = set_option_space(ctx, arg, &d, &dl, ifo,
                    &request, &require, &no);
                if (make_option_mask(d, dl, require, arg, 1) != 0 ||
                    make_option_mask(d, dl, request, arg, 1) != 0)
@@ -1077,7 +1071,8 @@ parse_option(const char *ifname, struct if_options *ifo,
                ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
                break;
        case 'Z':
-               ifdv = splitv(&ifdc, ifdv, arg);
+               if (ifname == NULL)
+                       ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg);
                break;
        case '4':
                ifo->options &= ~DHCPCD_IPV6;
@@ -1113,7 +1108,7 @@ parse_option(const char *ifname, struct if_options *ifo,
                }
                break;
        case O_DESTINATION:
-               if (make_option_mask(dhcp_opts, dhcp_opts_len,
+               if (make_option_mask(ctx->dhcp_opts, ctx->dhcp_opts_len,
                    ifo->dstmask, arg, 2) != 0) {
                        if (errno == EINVAL)
                                syslog(LOG_ERR, "option `%s' does not take"
@@ -1302,9 +1297,11 @@ parse_option(const char *ifname, struct if_options *ifo,
                ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
                break;
        case O_DEV:
-               if (dev_load)
-                       free(dev_load);
-               dev_load = strdup(arg);
+#ifdef PLUGIN_DEV
+               if (ctx->dev_load)
+                       free(ctx->dev_load);
+               ctx->dev_load = strdup(arg);
+#endif
                break;
        case O_NODEV:
                ifo->options &= ~DHCPCD_DEV;
@@ -1324,16 +1321,16 @@ parse_option(const char *ifname, struct if_options *ifo,
                        dop = &ifo->vivso_override;
                        dop_len = &ifo->vivso_override_len;
                }
-               edop = ldop = NULL;
+               *edop = *ldop = NULL;
                /* FALLTHROUGH */
        case O_EMBED:
                if (dop == NULL) {
-                       if (edop) {
-                               dop = &edop->embopts;
-                               dop_len = &edop->embopts_len;
+                       if (*edop) {
+                               dop = &(*edop)->embopts;
+                               dop_len = &(*edop)->embopts_len;
                        } else if (ldop) {
-                               dop = &ldop->embopts;
-                               dop_len = &ldop->embopts_len;
+                               dop = &(*ldop)->embopts;
+                               dop_len = &(*ldop)->embopts_len;
                        } else {
                                syslog(LOG_ERR,
                                    "embed must be after a define or encap");
@@ -1343,12 +1340,12 @@ parse_option(const char *ifname, struct if_options *ifo,
                /* FALLTHROUGH */
        case O_ENCAP:
                if (dop == NULL) {
-                       if (ldop == NULL) {
+                       if (*ldop == NULL) {
                                syslog(LOG_ERR, "encap must be after a define");
                                return -1;
                        }
-                       dop = &ldop->encopts;
-                       dop_len = &ldop->encopts_len;
+                       dop = &(*ldop)->encopts;
+                       dop_len = &(*ldop)->encopts_len;
                }
 
                /* Shared code for define, define6, embed and encap */
@@ -1526,9 +1523,9 @@ parse_option(const char *ifname, struct if_options *ifo,
                ndop->var = np;
                /* Save the define for embed and encap options */
                if (opt == O_DEFINE || opt == O_DEFINE6 || opt == O_VENDOPT)
-                       ldop = ndop;
+                       *ldop = ndop;
                else if (opt == O_ENCAP)
-                       edop = ndop;
+                       *edop = ndop;
                break;
        case O_VENDCLASS:
                fp = strwhite(arg);
@@ -1720,8 +1717,9 @@ parse_option(const char *ifname, struct if_options *ifo,
 }
 
 static int
-parse_config_line(const char *ifname, struct if_options *ifo,
-    const char *opt, char *line)
+parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname,
+    struct if_options *ifo, const char *opt, char *line,
+    struct dhcp_opt **ldop, struct dhcp_opt **edop)
 {
        unsigned int i;
 
@@ -1737,10 +1735,11 @@ parse_config_line(const char *ifname, struct if_options *ifo,
                        return -1;
                }
 
-               return parse_option(ifname, ifo, cf_options[i].val, line);
+               return parse_option(ctx, ifname, ifo, cf_options[i].val, line,
+                   ldop, edop);
        }
 
-       fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
+       syslog(LOG_ERR, "unknown option: %s", opt);
        return -1;
 }
 
@@ -1764,7 +1763,8 @@ finish_config(struct if_options *ifo)
  * We strip leading space and avoid comment lines, making the code that calls
  * us smaller. */
 static char *
-get_line(char ** __restrict buf, size_t * __restrict buflen, FILE * __restrict fp)
+get_line(char ** __restrict buf, size_t * __restrict buflen,
+    FILE * __restrict fp)
 {
        char *p;
        ssize_t bytes;
@@ -1782,7 +1782,7 @@ get_line(char ** __restrict buf, size_t * __restrict buflen, FILE * __restrict f
 }
 
 struct if_options *
-read_config(const char *file,
+read_config(struct dhcpcd_ctx *ctx,
     const char *ifname, const char *ssid, const char *profile)
 {
        struct if_options *ifo;
@@ -1798,6 +1798,7 @@ read_config(const char *file,
        size_t i;
        struct dhcp_opt *opt;
 #endif
+       struct dhcp_opt *ldop, *edop;
 
        /* Seed our default options */
        ifo = calloc(1, sizeof(*ifo));
@@ -1866,6 +1867,7 @@ read_config(const char *file,
                        syslog(LOG_ERR, "%s: %m", __func__);
                        return NULL;
                }
+               ldop = edop = NULL;
                for (e = dhcpcd_embedded_conf; *e; e++) {
                        ol = strlen(*e) + 1;
                        if (ol > buflen) {
@@ -1891,7 +1893,8 @@ read_config(const char *file,
                                    *(p - 1) != '\\')
                                        *p-- = '\0';
                        }
-                       parse_config_line(NULL, ifo, option, line);
+                       parse_config_line(ctx, NULL, ifo, option, line,
+                           &ldop, &edop);
 
                }
 
@@ -1900,8 +1903,8 @@ read_config(const char *file,
                        fclose(fp);
 #endif
 #ifdef INET
-               dhcp_opts = ifo->dhcp_override;
-               dhcp_opts_len = ifo->dhcp_override_len;
+               ctx->dhcp_opts = ifo->dhcp_override;
+               ctx->dhcp_opts_len = ifo->dhcp_override_len;
 #else
                for (i = 0, opt = ifo->dhcp_override;
                    i < ifo->dhcp_override_len;
@@ -1913,8 +1916,8 @@ read_config(const char *file,
                ifo->dhcp_override_len = 0;
 
 #ifdef INET6
-               dhcp6_opts = ifo->dhcp6_override;
-               dhcp6_opts_len = ifo->dhcp6_override_len;
+               ctx->dhcp6_opts = ifo->dhcp6_override;
+               ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
 #else
                for (i = 0, opt = ifo->dhcp6_override;
                    i < ifo->dhcp6_override_len;
@@ -1925,21 +1928,22 @@ read_config(const char *file,
                ifo->dhcp6_override = NULL;
                ifo->dhcp6_override_len = 0;
 
-               vivso = ifo->vivso_override;
-               vivso_len = ifo->vivso_override_len;
+               ctx->vivso = ifo->vivso_override;
+               ctx->vivso_len = ifo->vivso_override_len;
                ifo->vivso_override = NULL;
                ifo->vivso_override_len = 0;
        }
 
        /* Parse our options file */
-       fp = fopen(file ? file : CONFIG, "r");
+       fp = fopen(ctx->cffile, "r");
        if (fp == NULL) {
-               if (file != NULL)
-                       syslog(LOG_ERR, "fopen `%s': %m", file);
+               if (strcmp(ctx->cffile, CONFIG))
+                       syslog(LOG_ERR, "fopen `%s': %m", ctx->cffile);
                free(buf);
                return ifo;
        }
 
+       ldop = edop = NULL;
        while ((line = get_line(&buf, &buflen, fp))) {
                option = strsep(&line, " \t");
                if (line)
@@ -1979,7 +1983,7 @@ read_config(const char *file,
                }
                if (skip)
                        continue;
-               parse_config_line(ifname, ifo, option, line);
+               parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
        }
        fclose(fp);
        free(buf);
@@ -1995,7 +1999,8 @@ read_config(const char *file,
 }
 
 int
-add_options(const char *ifname, struct if_options *ifo, int argc, char **argv)
+add_options(struct dhcpcd_ctx *ctx, const char *ifname,
+    struct if_options *ifo, int argc, char **argv)
 {
        int oi, opt, r;
 
@@ -2006,7 +2011,7 @@ add_options(const char *ifname, struct if_options *ifo, int argc, char **argv)
        r = 1;
        while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
        {
-               r = parse_option(ifname, ifo, opt, optarg);
+               r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
                if (r != 1)
                        break;
        }
index 77c0c3e59ae1f0a4d85c200adf35dc1db83b108d..138c0bdc5dd9abb8c676942da133bac30c08bb0c 100644 (file)
@@ -183,12 +183,10 @@ struct if_options {
        struct auth auth;
 };
 
-extern unsigned long long options;
-extern char *dev_load;
-
-struct if_options *read_config(const char *,
+struct if_options *read_config(struct dhcpcd_ctx *,
     const char *, const char *, const char *);
-int add_options(const char *, struct if_options *, int, char **);
+int add_options(struct dhcpcd_ctx *, const char *,
+    struct if_options *, int, char **);
 void free_dhcp_opt_embenc(struct dhcp_opt *);
 void free_options(struct if_options *);
 
index 60a5b12f1c29fafd4fb0527e1d3dcc5077024ae9..47694457485351a8ad3631058ae5cf4093fadd0c 100644 (file)
--- a/if-pref.c
+++ b/if-pref.c
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -77,21 +77,21 @@ ifcmp(const struct interface *si, const struct interface *ti)
 
 /* Sort the interfaces into a preferred order - best first, worst last. */
 void
-sort_interfaces(void)
+sort_interfaces(struct dhcpcd_ctx *ctx)
 {
        struct if_head sorted;
        struct interface *ifp, *ift;
 
-       if (ifaces == NULL ||
-           (ifp = TAILQ_FIRST(ifaces)) == NULL ||
+       if (ctx->ifaces == NULL ||
+           (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL ||
            TAILQ_NEXT(ifp, next) == NULL)
                return;
 
        TAILQ_INIT(&sorted);
-       TAILQ_REMOVE(ifaces, ifp, next);
+       TAILQ_REMOVE(ctx->ifaces, ifp, next);
        TAILQ_INSERT_HEAD(&sorted, ifp, next);
-       while ((ifp = TAILQ_FIRST(ifaces))) {
-               TAILQ_REMOVE(ifaces, ifp, next);
+       while ((ifp = TAILQ_FIRST(ctx->ifaces))) {
+               TAILQ_REMOVE(ctx->ifaces, ifp, next);
                TAILQ_FOREACH(ift, &sorted, next) {
                        if (ifcmp(ifp, ift) == -1) {
                                TAILQ_INSERT_BEFORE(ift, ifp, next);
@@ -101,5 +101,5 @@ sort_interfaces(void)
                if (ift == NULL)
                        TAILQ_INSERT_TAIL(&sorted, ifp, next);
        }
-       TAILQ_CONCAT(ifaces, &sorted, next);
+       TAILQ_CONCAT(ctx->ifaces, &sorted, next);
 }
index bea453b28bf6fd773cb2ecee2b87bed5f48423db..43c84bc2940683ca8132de3c45fd134f7a3a0f64 100644 (file)
--- a/if-pref.h
+++ b/if-pref.h
@@ -30,5 +30,5 @@
 
 #include "dhcpcd.h"
 
-void sort_interfaces(void);
+void sort_interfaces(struct dhcpcd_ctx *);
 #endif
diff --git a/ipv4.c b/ipv4.c
index e439156232589f4d4274243f93fe740ed06d2927..d6751cb5e3080475a4f0638f3c47d4796674b8fa 100644 (file)
--- a/ipv4.c
+++ b/ipv4.c
@@ -61,8 +61,6 @@
 #undef IPV4_LOOPBACK_ROUTE
 #endif
 
-static struct rt_head *routes;
-
 int
 inet_ntocidr(struct in_addr address)
 {
@@ -135,12 +133,12 @@ ipv4_findaddr(struct interface *ifp,
 }
 
 int
-ipv4_addrexists(const struct in_addr *addr)
+ipv4_addrexists(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
 {
        struct interface *ifp;
        struct dhcp_state *state;
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                state = D_STATE(ifp);
                if (state) {
                        if (addr == NULL) {
@@ -170,14 +168,14 @@ ipv4_freeroutes(struct rt_head *rts)
 }
 
 int
-ipv4_init(void)
+ipv4_init(struct dhcpcd_ctx *ctx)
 {
 
-       if (routes == NULL) {
-               routes = malloc(sizeof(*routes));
-               if (routes == NULL)
+       if (ctx->ipv4_routes == NULL) {
+               ctx->ipv4_routes = malloc(sizeof(*ctx->ipv4_routes));
+               if (ctx->ipv4_routes == NULL)
                        return -1;
-               TAILQ_INIT(routes);
+               TAILQ_INIT(ctx->ipv4_routes);
        }
        return 0;
 }
@@ -231,15 +229,15 @@ desc_route(const char *cmd, const struct rt *rt)
 /* If something other than dhcpcd removes a route,
  * we need to remove it from our internal table. */
 int
-ipv4_routedeleted(const struct rt *rt)
+ipv4_routedeleted(struct dhcpcd_ctx *ctx, const struct rt *rt)
 {
        struct rt *f;
 
-       f = find_route(routes, rt, NULL);
+       f = find_route(ctx->ipv4_routes, rt, NULL);
        if (f == NULL)
                return 0;
        desc_route("removing", f);
-       TAILQ_REMOVE(routes, f, next);
+       TAILQ_REMOVE(ctx->ipv4_routes, f, next);
        free(f);
        return 1;
 }
@@ -281,7 +279,7 @@ d_route(struct rt *rt)
 }
 
 static struct rt *
-get_subnet_route(struct dhcp_message *dhcp)
+get_subnet_route(struct dhcpcd_ctx *ctx, struct dhcp_message *dhcp)
 {
        in_addr_t addr;
        struct in_addr net;
@@ -291,7 +289,7 @@ get_subnet_route(struct dhcp_message *dhcp)
        if (addr == 0)
                addr = dhcp->ciaddr;
        /* Ensure we have all the needed values */
-       if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
+       if (get_option_addr(ctx, &net, dhcp, DHO_SUBNETMASK) == -1)
                net.s_addr = ipv4_getnetmask(addr);
        if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
                return NULL;
@@ -484,7 +482,7 @@ add_router_host_route(struct rt_head *rt, const struct interface *ifp)
 }
 
 void
-ipv4_buildroutes(void)
+ipv4_buildroutes(struct dhcpcd_ctx *ctx)
 {
        struct rt_head *nrs, *dnr;
        struct rt *or, *rt, *rtn;
@@ -497,7 +495,7 @@ ipv4_buildroutes(void)
                return;
        }
        TAILQ_INIT(nrs);
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                state = D_CSTATE(ifp);
                if (state == NULL || state->new == NULL)
                        continue;
@@ -521,7 +519,7 @@ ipv4_buildroutes(void)
                                continue;
                        rt->src.s_addr = state->addr.s_addr;
                        /* Do we already manage it? */
-                       if ((or = find_route(routes, rt, NULL))) {
+                       if ((or = find_route(ctx->ipv4_routes, rt, NULL))) {
                                if (or->iface != ifp ||
                                    or->src.s_addr != state->addr.s_addr ||
                                    rt->gate.s_addr != or->gate.s_addr ||
@@ -530,7 +528,7 @@ ipv4_buildroutes(void)
                                        if (c_route(or, rt) != 0)
                                                continue;
                                }
-                               TAILQ_REMOVE(routes, or, next);
+                               TAILQ_REMOVE(ctx->ipv4_routes, or, next);
                                free(or);
                        } else {
                                if (n_route(rt) != 0)
@@ -543,13 +541,13 @@ ipv4_buildroutes(void)
        }
 
        /* Remove old routes we used to manage */
-       TAILQ_FOREACH(rt, routes, next) {
+       TAILQ_FOREACH(rt, ctx->ipv4_routes, next) {
                if (find_route(nrs, rt, NULL) == NULL)
                        d_route(rt);
        }
-       ipv4_freeroutes(routes);
+       ipv4_freeroutes(ctx->ipv4_routes);
 
-       routes = nrs;
+       ctx->ipv4_routes = nrs;
 }
 
 static int
@@ -631,7 +629,7 @@ ipv4_applyaddr(void *arg)
 
        /* As we are now adjusting an interface, we need to ensure
         * we have them in the right order for routing and configuration. */
-       sort_interfaces();
+       sort_interfaces(ifp->ctx);
 
        if (state == NULL)
                return;
@@ -642,7 +640,7 @@ ipv4_applyaddr(void *arg)
                if ((ifo->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
                    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
                {
-                       ipv4_buildroutes();
+                       ipv4_buildroutes(ifp->ctx);
                        if (state->addr.s_addr != 0)
                                delete_address(ifp);
                        script_runreason(ifp, state->reason);
@@ -691,16 +689,16 @@ ipv4_applyaddr(void *arg)
 
        /* We need to delete the subnet route to have our metric or
         * prefer the interface. */
-       rt = get_subnet_route(dhcp);
+       rt = get_subnet_route(ifp->ctx, dhcp);
        if (rt != NULL) {
                rt->iface = ifp;
                rt->metric = 0;
-               if (!find_route(routes, rt, NULL))
+               if (!find_route(ifp->ctx->ipv4_routes, rt, NULL))
                        ipv4_deleteroute(rt);
                free(rt);
        }
 
-       ipv4_buildroutes();
+       ipv4_buildroutes(ifp->ctx);
        if (!state->lease.frominfo &&
            !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
                if (write_lease(ifp, dhcp) == -1)
@@ -709,7 +707,8 @@ ipv4_applyaddr(void *arg)
 }
 
 void
-ipv4_handleifa(int type, struct if_head *ifs, const char *ifname,
+ipv4_handleifa(struct dhcpcd_ctx *ctx,
+    int type, struct if_head *ifs, const char *ifname,
     const struct in_addr *addr, const struct in_addr *net,
     const struct in_addr *dst)
 {
@@ -718,7 +717,7 @@ ipv4_handleifa(int type, struct if_head *ifs, const char *ifname,
        struct ipv4_addr *ap;
 
        if (ifs == NULL)
-               ifs = ifaces;
+               ifs = ctx->ifaces;
        if (ifs == NULL)
                return;
        if (addr->s_addr == INADDR_ANY)
@@ -773,8 +772,12 @@ ipv4_free(struct interface *ifp)
                        }
                        free(state);
                }
-       } else {
-               ipv4_freeroutes(routes);
-               routes = NULL;
        }
 }
+
+void
+ipv4_ctxfree(struct dhcpcd_ctx *ctx)
+{
+
+       ipv4_freeroutes(ctx->ipv4_routes);
+}
diff --git a/ipv4.h b/ipv4.h
index bf85294b4bfdeeedf386236b051d9df8a5e8b549..1fda9ba665a0d2ebabcc1631d45b62c67d4ff638 100644 (file)
--- a/ipv4.h
+++ b/ipv4.h
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -59,19 +59,19 @@ struct ipv4_state {
        ((const struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
 
 #ifdef INET
-int ipv4_init(void);
+int ipv4_init(struct dhcpcd_ctx *);
 int inet_ntocidr(struct in_addr);
 int inet_cidrtoaddr(int, struct in_addr *);
 uint32_t ipv4_getnetmask(uint32_t);
-int ipv4_addrexists(const struct in_addr *);
+int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *);
 
-void ipv4_buildroutes(void);
+void ipv4_buildroutes(struct dhcpcd_ctx *);
 void ipv4_applyaddr(void *);
-int ipv4_routedeleted(const struct rt *);
+int ipv4_routedeleted(struct dhcpcd_ctx *, const struct rt *);
 
 struct ipv4_addr *ipv4_findaddr(struct interface *,
     const struct in_addr *, const struct in_addr *);
-void ipv4_handleifa(int, struct if_head *, const char *,
+void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *,
     const struct in_addr *, const struct in_addr *, const struct in_addr *);
 
 int if_address(const struct interface *,
@@ -96,11 +96,13 @@ ssize_t ipv4_sendrawpacket(const struct interface *,
     int, const void *, ssize_t);
 ssize_t ipv4_getrawpacket(struct interface *, int, void *, ssize_t, int *);
 void ipv4_free(struct interface *);
+void ipv4_ctxfree(struct dhcpcd_ctx *);
 #else
 #define ipv4_init() (-1)
 #define ipv4_applyaddr(a) {}
 #define ipv4_freeroutes(a) {}
 #define ipv4_free(a) {}
+#define ipv4_ctxfree(a) {}
 #define ipv4_addrexists(a) (0)
 #endif
 
index b32b9f693d093e654de3c28b89755ed9db488fc5..83d96cb923d6df3faa8f9768938a28955d5da0ff 100644 (file)
--- a/ipv4ll.c
+++ b/ipv4ll.c
@@ -92,7 +92,7 @@ ipv4ll_start(void *arg)
        struct dhcp_state *state = D_STATE(ifp);
        uint32_t addr;
 
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        state->probes = 0;
        state->claims = 0;
        if (state->addr.s_addr) {
@@ -153,7 +153,7 @@ ipv4ll_handle_failure(void *arg)
 
        free(state->offer);
        state->offer = NULL;
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        if (++state->conflicts > MAX_CONFLICTS) {
                syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
                    ifp->name);
@@ -161,9 +161,10 @@ ipv4ll_handle_failure(void *arg)
                        state->interval = RATE_LIMIT_INTERVAL / 2;
                        dhcp_discover(ifp);
                } else
-                       eloop_timeout_add_sec(RATE_LIMIT_INTERVAL,
-                           ipv4ll_start, ifp);
+                       eloop_timeout_add_sec(ifp->ctx->eloop,
+                           RATE_LIMIT_INTERVAL, ipv4ll_start, ifp);
        } else {
-               eloop_timeout_add_sec(PROBE_WAIT, ipv4ll_start, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   PROBE_WAIT, ipv4ll_start, ifp);
        }
 }
diff --git a/ipv6.c b/ipv6.c
index d5473f17e12c1c63602c2dac83b1763f6c2501f1..8cab5934190f78f4165e692605d27264beeae64a 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
                                    while (/*CONSTCOND*/ 0)
 #define EUI64_GROUP(in6)       ((in6)->s6_addr[8] & EUI64_GBIT)
 
-static struct rt6head *routes;
 
-int
-ipv6_init(void)
+struct ipv6_ctx *
+ipv6_init(struct dhcpcd_ctx *dhcpcd_ctx)
 {
+       struct ipv6_ctx *ctx;
 
-       if (routes == NULL) {
-               routes = malloc(sizeof(*routes));
-               if (routes == NULL)
-                       return -1;
-               TAILQ_INIT(routes);
+       if (dhcpcd_ctx->ipv6)
+               return dhcpcd_ctx->ipv6;
+
+       ctx = calloc(1, sizeof(*ctx));
+       if (ctx == NULL)
+               return NULL;
+
+       ctx->routes = malloc(sizeof(*ctx->routes));
+       if (ctx->routes == NULL) {
+               free(ctx);
+               return NULL;
        }
-       return 0;
+       TAILQ_INIT(ctx->routes);
+
+       ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
+       if (ctx->ra_routers == NULL) {
+               free(ctx->routes);
+               free(ctx);
+               return NULL;
+       }
+       TAILQ_INIT(ctx->ra_routers);
+
+       ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
+       ctx->sndhdr.msg_iov = ctx->sndiov;
+       ctx->sndhdr.msg_iovlen = 1;
+       ctx->sndhdr.msg_control = ctx->sndbuf;
+       ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
+       ctx->rcvhdr.msg_name = &ctx->from;
+       ctx->rcvhdr.msg_namelen = sizeof(ctx->from);
+       ctx->rcvhdr.msg_iov = ctx->rcviov;
+       ctx->rcvhdr.msg_iovlen = 1;
+       ctx->rcvhdr.msg_control = ctx->rcvbuf;
+       ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf);
+       ctx->rcviov[0].iov_base = ctx->ansbuf;
+       ctx->rcviov[0].iov_len = sizeof(ctx->ansbuf);
+
+       ctx->nd_fd = -1;
+       ctx->dhcp_fd = -1;
+
+       dhcpcd_ctx->ipv6 = ctx;
+       return ctx;
 }
 
 ssize_t
@@ -435,12 +469,14 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
                        continue;
                TAILQ_REMOVE(addrs, ap, next);
                if (ap->dadcallback)
-                       eloop_q_timeout_delete(0, NULL, ap->dadcallback);
+                       eloop_q_timeout_delete(ap->iface->ctx->eloop,
+                           0, NULL, ap->dadcallback);
                /* Only drop the address if no other RAs have assigned it.
                 * This is safe because the RA is removed from the list
                 * before we are called. */
                if (drop && ap->flags & IPV6_AF_ADDED &&
-                   !ipv6nd_addrexists(ap) && !dhcp6_addrexists(ap) &&
+                   !ipv6nd_addrexists(ap->iface->ctx, ap) &&
+                   !dhcp6_addrexists(ap->iface->ctx, ap) &&
                    (ap->iface->options->options &
                    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
                    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
@@ -475,7 +511,8 @@ ipv6_getstate(struct interface *ifp)
 }
 
 void
-ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
+ipv6_handleifa(struct dhcpcd_ctx *ctx,
+    int cmd, struct if_head *ifs, const char *ifname,
     const struct in6_addr *addr, int flags)
 {
        struct interface *ifp;
@@ -502,7 +539,7 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
        }
 
        if (ifs == NULL)
-               ifs = ifaces;
+               ifs = ctx->ifaces;
        if (ifs == NULL) {
                errno = ESRCH;
                return;
@@ -521,8 +558,8 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
                return;
 
        if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
-               ipv6nd_handleifa(cmd, ifname, addr, flags);
-               dhcp6_handleifa(cmd, ifname, addr, flags);
+               ipv6nd_handleifa(ctx, cmd, ifname, addr, flags);
+               dhcp6_handleifa(ctx, cmd, ifname, addr, flags);
        }
 
        /* We don't care about duplicated addresses, so remove them */
@@ -642,7 +679,6 @@ ipv6_free(struct interface *ifp)
 {
        struct ipv6_state *state;
        struct ipv6_addr_l *ap;
-       struct rt6 *rt;
 
        if (ifp) {
                ipv6_free_ll_callbacks(ifp);
@@ -655,18 +691,21 @@ ipv6_free(struct interface *ifp)
                        free(state);
                        ifp->if_data[IF_DATA_IPV6] = NULL;
                }
-       } else {
-               if (routes) {
-                       while ((rt = TAILQ_FIRST(routes))) {
-                               TAILQ_REMOVE(routes, rt, next);
-                               free(rt);
-                       }
-                       free(routes);
-                       routes = NULL;
-               }
        }
 }
 
+void
+ipv6_ctxfree(struct dhcpcd_ctx *ctx)
+{
+
+       if (ctx->ipv6 == NULL)
+               return;
+
+       free(ctx->ipv6->routes);
+       free(ctx->ipv6->ra_routers);
+       free(ctx->ipv6);
+}
+
 int
 ipv6_handleifa_addrs(int cmd,
     struct ipv6_addrhead *addrs, const struct in6_addr *addr, int flags)
@@ -713,7 +752,7 @@ ipv6_handleifa_addrs(int cmd,
 }
 
 static struct rt6 *
-find_route6(struct rt6head *rts, const struct rt6 *r)
+find_route6(struct rt6_head *rts, const struct rt6 *r)
 {
        struct rt6 *rt;
 
@@ -844,7 +883,7 @@ make_router(const struct ra *rap)
 }
 
 int
-ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr)
+ipv6_removesubnet(struct interface *ifp, struct ipv6_addr *addr)
 {
        struct rt6 *rt;
 #if HAVE_ROUTE_METRIC
@@ -867,10 +906,10 @@ ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr)
                /* For some reason, Linux likes to re-add the subnet
                   route under the original metric.
                   I would love to find a way of stopping this! */
-               if ((ort = find_route6(routes, rt)) == NULL ||
+               if ((ort = find_route6(ifp->ctx->ipv6->routes, rt)) == NULL ||
                    ort->metric != rt->metric)
 #else
-               if (!find_route6(routes, rt))
+               if (!find_route6(ifp->ctx->ipv6->routes, rt))
 #endif
                {
                        r = del_route6(rt);
@@ -887,13 +926,13 @@ ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr)
            IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any))
 
 static void
-ipv6_build_ra_routes(struct rt6head *dnr, int expired)
+ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired)
 {
        struct rt6 *rt;
        const struct ra *rap;
        const struct ipv6_addr *addr;
 
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ctx->ra_routers, next) {
                if (rap->expired != expired)
                        continue;
                if (rap->iface->options->options & DHCPCD_IPV6RA_OWN) {
@@ -916,14 +955,15 @@ ipv6_build_ra_routes(struct rt6head *dnr, int expired)
 }
 
 static void
-ipv6_build_dhcp_routes(struct rt6head *dnr, enum DH6S dstate)
+ipv6_build_dhcp_routes(struct dhcpcd_ctx *ctx,
+    struct rt6_head *dnr, enum DH6S dstate)
 {
        const struct interface *ifp;
        const struct dhcp6_state *d6_state;
        const struct ipv6_addr *addr;
        struct rt6 *rt;
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                if (!(ifp->options->options & DHCPCD_IPV6RA_OWN))
                        continue;
                d6_state = D6_CSTATE(ifp);
@@ -941,9 +981,9 @@ ipv6_build_dhcp_routes(struct rt6head *dnr, enum DH6S dstate)
 }
 
 void
-ipv6_buildroutes(void)
+ipv6_buildroutes(struct dhcpcd_ctx *ctx)
 {
-       struct rt6head dnr, *nrs;
+       struct rt6_head dnr, *nrs;
        struct rt6 *rt, *rtn, *or;
        uint8_t have_default;
        unsigned long long o;
@@ -951,7 +991,7 @@ ipv6_buildroutes(void)
        TAILQ_INIT(&dnr);
 
        /* First add reachable routers and their prefixes */
-       ipv6_build_ra_routes(&dnr, 0);
+       ipv6_build_ra_routes(ctx->ipv6, &dnr, 0);
 #if HAVE_ROUTE_METRIC
        have_default = (TAILQ_FIRST(&dnr) != NULL);
 #endif
@@ -959,8 +999,8 @@ ipv6_buildroutes(void)
        /* We have no way of knowing if prefixes added by DHCP are reachable
         * or not, so we have to assume they are.
         * Add bound before delegated so we can prefer interfaces better */
-       ipv6_build_dhcp_routes(&dnr, DH6S_BOUND);
-       ipv6_build_dhcp_routes(&dnr, DH6S_DELEGATED);
+       ipv6_build_dhcp_routes(ctx, &dnr, DH6S_BOUND);
+       ipv6_build_dhcp_routes(ctx, &dnr, DH6S_DELEGATED);
 
 #if HAVE_ROUTE_METRIC
        /* If we have an unreachable router, we really do need to remove the
@@ -972,7 +1012,7 @@ ipv6_buildroutes(void)
        /* Add our non-reachable routers and prefixes
         * Unsure if this is needed, but it's a close match to kernel
         * behaviour */
-       ipv6_build_ra_routes(&dnr, 1);
+       ipv6_build_ra_routes(ctx->ipv6, &dnr, 1);
 
        nrs = malloc(sizeof(*nrs));
        if (nrs == NULL) {
@@ -987,7 +1027,7 @@ ipv6_buildroutes(void)
                        continue;
                //rt->src.s_addr = ifp->addr.s_addr;
                /* Do we already manage it? */
-               if ((or = find_route6(routes, rt))) {
+               if ((or = find_route6(ctx->ipv6->routes, rt))) {
                        if (or->iface != rt->iface ||
                //          or->src.s_addr != ifp->addr.s_addr ||
                            !IN6_ARE_ADDR_EQUAL(&rt->gate, &or->gate) ||
@@ -996,7 +1036,7 @@ ipv6_buildroutes(void)
                                if (c_route(or, rt) != 0)
                                        continue;
                        }
-                       TAILQ_REMOVE(routes, or, next);
+                       TAILQ_REMOVE(ctx->ipv6->routes, or, next);
                        free(or);
                } else {
                        if (n_route(rt) != 0)
@@ -1017,8 +1057,8 @@ ipv6_buildroutes(void)
        /* Remove old routes we used to manage
         * If we own the default route, but not RA management itself
         * then we need to preserve the last best default route we had */
-       while ((rt = TAILQ_LAST(routes, rt6head))) {
-               TAILQ_REMOVE(routes, rt, next);
+       while ((rt = TAILQ_LAST(ctx->ipv6->routes, rt6_head))) {
+               TAILQ_REMOVE(ctx->ipv6->routes, rt, next);
                if (find_route6(nrs, rt) == NULL) {
                        o = rt->iface->options->options;
                        if (!have_default &&
@@ -1037,6 +1077,6 @@ ipv6_buildroutes(void)
                free(rt);
        }
 
-       free(routes);
-       routes = nrs;
+       free(ctx->ipv6->routes);
+       ctx->ipv6->routes = nrs;
 }
diff --git a/ipv6.h b/ipv6.h
index 6b5dc1dfd0be36f651abec61c9c6c4491654b28f..b070696e49225acb38614c1029b270fcbaaf4b2a 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
 
 #include <netinet/in.h>
 
+#ifdef __linux__
+#  define _LINUX_IN6_H
+#  include <linux/ipv6.h>
+#endif
+
+#include "dhcpcd.h"
+
 #define ALLROUTERS "ff02::2"
 #define HOPLIMIT 255
 
@@ -104,7 +111,7 @@ struct rt6 {
        int metric;
        unsigned int mtu;
 };
-TAILQ_HEAD(rt6head, rt6);
+TAILQ_HEAD(rt6_head, rt6);
 
 struct ipv6_addr_l {
        TAILQ_ENTRY(ipv6_addr_l) next;
@@ -130,8 +137,33 @@ struct ipv6_state {
 #define IPV6_CSTATE(ifp)                                                      \
        ((const struct ipv6_state *)(ifp)->if_data[IF_DATA_IPV6])
 
+#define IP6BUFLEN      (CMSG_SPACE(sizeof(struct in6_pktinfo)) + \
+                       CMSG_SPACE(sizeof(int)))
+
+struct ipv6_ctx {
+       struct sockaddr_in6 from;
+       struct msghdr sndhdr;
+       struct iovec sndiov[2];
+       unsigned char sndbuf[IP6BUFLEN];
+       struct msghdr rcvhdr;
+       struct iovec rcviov[2];
+       unsigned char rcvbuf[IP6BUFLEN];
+       unsigned char ansbuf[1500];
+       char ntopbuf[INET6_ADDRSTRLEN];
+       const char *sfrom;
+
+       int nd_fd;
+#ifdef IPV6_SEND_DAD
+       int unspec_fd = -1;
+#endif
+       struct ra_head *ra_routers;
+       struct rt6_head *routes;
+
+       int dhcp_fd;
+};
+
 #ifdef INET6
-int ipv6_init(void);
+struct ipv6_ctx *ipv6_init(struct dhcpcd_ctx *);
 ssize_t ipv6_printaddr(char *, ssize_t, const uint8_t *, const char *);
 int ipv6_makeaddr(struct in6_addr *, const struct interface *,
     const struct in6_addr *, int);
@@ -143,7 +175,7 @@ int ipv6_userprefix( const struct in6_addr *, short prefix_len,
 int ipv6_addaddr(struct ipv6_addr *);
 void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,
     const struct interface *);
-void ipv6_handleifa(int, struct if_head *,
+void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
     const char *, const struct in6_addr *, int);
 int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
     const struct in6_addr *, int);
@@ -153,8 +185,9 @@ const struct ipv6_addr_l *ipv6_findaddr(const struct interface *,
 int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
 void ipv6_free_ll_callbacks(struct interface *);
 void ipv6_free(struct interface *);
-int ipv6_removesubnet(const struct interface *, struct ipv6_addr *);
-void ipv6_buildroutes(void);
+void ipv6_ctxfree(struct dhcpcd_ctx *);
+int ipv6_removesubnet(struct interface *, struct ipv6_addr *);
+void ipv6_buildroutes(struct dhcpcd_ctx *);
 
 int if_address6(const struct ipv6_addr *, int);
 #define add_address6(a) if_address6(a, 1)
@@ -171,6 +204,7 @@ int if_route6(const struct rt6 *rt, int);
 #define ipv6_init() -1
 #define ipv6_free_ll_callbacks(a)
 #define ipv6_free(a)
+#define ipv6_ctxfree(a)
 #endif
 
 #endif
index 874a1ea592aaf39d29871174de0c8f8bffa3cf03..a4300be9e1e7296889469e5f092ccb5b00489b97 100644 (file)
--- a/ipv6nd.c
+++ b/ipv6nd.c
 #include <syslog.h>
 #include <unistd.h>
 
+/* 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
+
 #define ELOOP_QUEUE 2
 #include "common.h"
 #include "dhcpcd.h"
@@ -124,32 +132,6 @@ struct nd_opt_dnssl {              /* DNSSL option RFC 6106 */
 //#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];
-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 const char *sfrom;
-static struct icmp6_filter filt;
-
-struct rahead ipv6_routers = TAILQ_HEAD_INITIALIZER(ipv6_routers);
-
 static void ipv6nd_handledata(void *arg);
 
 /*
@@ -181,10 +163,11 @@ static void ipv6nd_handledata(void *arg);
 #endif
 
 static int
-ipv6nd_open(void)
+ipv6nd_open(struct dhcpcd_ctx *dctx)
 {
+       struct ipv6_ctx *ctx;
        int on;
-       int len;
+       struct icmp6_filter filt;
 #ifdef IPV6_SEND_DAD
        union {
                struct sockaddr sa;
@@ -192,125 +175,75 @@ ipv6nd_open(void)
        } su;
 #endif
 
-       sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+       ctx = dctx->ipv6;
+       if (ctx->nd_fd != -1)
+               goto unspec;
+       ctx->nd_fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
            IPPROTO_ICMPV6);
-       if (sock == -1)
+       if (ctx->nd_fd == -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)
-               goto eexit;
        on = 1;
-       if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
-               &on, sizeof(on)) == -1)
+       if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+           &on, sizeof(on)) == -1)
                goto eexit;
 
        on = 1;
-       if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
-               &on, sizeof(on)) == -1)
+       if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+           &on, sizeof(on)) == -1)
                goto eexit;
 
        ICMP6_FILTER_SETBLOCKALL(&filt);
+       ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
        ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
-       if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
-               &filt, sizeof(filt)) == -1)
-               goto eexit;
-
-       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)
+       if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
+           &filt, sizeof(filt)) == -1)
                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);
-       return sock;
 
-eexit:
-       close(sock);
-       sock = -1;
-       free(sndbuf);
-       sndbuf = NULL;
-       free(rcvbuf);
-       rcvbuf = NULL;
-       return -1;
-}
+       eloop_event_add(dctx->eloop, ctx->nd_fd, ipv6nd_handledata, dctx);
 
-static int
-ipv6nd_naopen(void)
-{
-       static int naopen = 0;
-       struct icmp6_filter unspec_filt;
+unspec:
 #ifdef IPV6_SEND_DAD
-       union {
-               struct sockaddr sa;
-               struct sockaddr_in6 sin;
-       } su;
-#endif
-
-       if (naopen)
-               return sock;
+       if (ctx->unspec_fd != -1)
+               return ctx->nd_fd;
 
-       ICMP6_FILTER_SETBLOCKALL(&unspec_filt);
+       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)
-               return -1;
-       if (setsockopt(unspec_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
-           &unspec_filt, sizeof(unspec_filt)) == -1)
+       ctx->unspec_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+       if (ctx->unspec_fd == -1)
+               goto eexit;
+       if (setsockopt(ctx->unspec_fd, 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)
+       if (bind(ctx->unspec_fd, &su.sa, sizeof(su.sin)) == -1)
                goto eexit;
 #endif
 
-       if (sock == -1) {
-               if (ipv6nd_open() == -1)
-                       goto eexit;
-               eloop_event_add(sock, ipv6nd_handledata, NULL);
-       }
-
-       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;
+       return ctx->nd_fd;
 
 eexit:
-       syslog(LOG_ERR, "%s: %m", __func__);
+       if (ctx->nd_fd != -1) {
+               close(ctx->nd_fd);
+               eloop_event_delete(dctx->eloop, ctx->nd_fd);
+               ctx->nd_fd = -1;
+       }
 #ifdef IPV6_SEND_DAD
-       close(unspec_sock);
-       unspec_sock = -1;
+       if (ctx->unpsec_fd != -1) {
+               close(ctx->unspec_fd);
+               ctx->unspec_fd = -1;
+       }
 #endif
        return -1;
 }
@@ -344,6 +277,7 @@ static void
 ipv6nd_sendrsprobe(void *arg)
 {
        struct interface *ifp = arg;
+       struct ipv6_ctx *ctx;
        struct rs_state *state;
        struct sockaddr_in6 dst;
        struct cmsghdr *cm;
@@ -358,16 +292,25 @@ ipv6nd_sendrsprobe(void *arg)
                return;
        }
 
-       dst = allrouters;
+       memset(&dst, 0, sizeof(dst));
+       dst.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+       dst.sin6_len = sizeof(dst);
+#endif
        dst.sin6_scope_id = ifp->index;
+       if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr.s6_addr) != 1) {
+               syslog(LOG_ERR, "%s: %m", __func__);
+               return;
+       }
 
        state = RS_STATE(ifp);
-       sndhdr.msg_name = (caddr_t)&dst;
-       sndhdr.msg_iov[0].iov_base = state->rs;
-       sndhdr.msg_iov[0].iov_len = state->rslen;
+       ctx = ifp->ctx->ipv6;
+       ctx->sndhdr.msg_name = (caddr_t)&dst;
+       ctx->sndhdr.msg_iov[0].iov_base = state->rs;
+       ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
 
        /* Set the outbound interface */
-       cm = CMSG_FIRSTHDR(&sndhdr);
+       cm = CMSG_FIRSTHDR(&ctx->sndhdr);
        cm->cmsg_level = IPPROTO_IPV6;
        cm->cmsg_type = IPV6_PKTINFO;
        cm->cmsg_len = CMSG_LEN(sizeof(pi));
@@ -376,14 +319,14 @@ ipv6nd_sendrsprobe(void *arg)
        memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
 
        /* Hop limit */
-       cm = CMSG_NXTHDR(&sndhdr, cm);
+       cm = CMSG_NXTHDR(&ctx->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));
 
        syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name);
-       if (sendmsg(sock, &sndhdr, 0) == -1) {
+       if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
                syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
                ipv6nd_drop(ifp);
                ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
@@ -391,8 +334,8 @@ ipv6nd_sendrsprobe(void *arg)
        }
 
        if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
-               eloop_timeout_add_sec(RTR_SOLICITATION_INTERVAL,
-                   ipv6nd_sendrsprobe, ifp);
+               eloop_timeout_add_sec(ifp->ctx->eloop,
+                   RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
        else
                syslog(LOG_WARNING, "%s: no IPv6 Routers available", ifp->name);
 }
@@ -410,12 +353,12 @@ ipv6nd_free_opts(struct ra *rap)
 }
 
 int
-ipv6nd_addrexists(const struct ipv6_addr *addr)
+ipv6nd_addrexists(struct dhcpcd_ctx *ctx, const struct ipv6_addr *addr)
 {
        struct ra *rap;
        struct ipv6_addr *ap;
 
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
                TAILQ_FOREACH(ap, &rap->addrs, next) {
                        if (addr == NULL) {
                                if ((ap->flags &
@@ -432,10 +375,10 @@ ipv6nd_addrexists(const struct ipv6_addr *addr)
 void ipv6nd_freedrop_ra(struct ra *rap, int drop)
 {
 
-       eloop_timeout_delete(NULL, rap->iface);
-       eloop_timeout_delete(NULL, rap);
+       eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
+       eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
        if (!drop)
-               TAILQ_REMOVE(&ipv6_routers, rap, next);
+               TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next);
        ipv6_freedrop_addrs(&rap->addrs, drop, NULL);
        ipv6nd_free_opts(rap);
        free(rap->data);
@@ -448,6 +391,7 @@ ipv6nd_free(struct interface *ifp)
 {
        struct rs_state *state;
        struct ra *rap, *ran;
+       struct dhcpcd_ctx *ctx;
        ssize_t n;
 
        state = RS_STATE(ifp);
@@ -458,7 +402,7 @@ ipv6nd_free(struct interface *ifp)
        free(state);
        ifp->if_data[IF_DATA_IPV6ND] = NULL;
        n = 0;
-       TAILQ_FOREACH_SAFE(rap, &ipv6_routers, next, ran) {
+       TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
                if (rap->iface == ifp) {
                        ipv6nd_free_ra(rap);
                        n++;
@@ -467,20 +411,17 @@ ipv6nd_free(struct interface *ifp)
 
        /* If we don't have any more IPv6 enabled interfaces,
         * close the global socket and release resources */
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       ctx = ifp->ctx;
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
                if (RS_STATE(ifp))
                        break;
        }
        if (ifp == NULL) {
-               if (sock != -1) {
-                           close(sock);
-                           eloop_event_delete(sock);
-                           sock = -1;
+               if (ctx->ipv6->nd_fd != -1) {
+                       close(ctx->ipv6->nd_fd);
+                       eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd);
+                       ctx->ipv6->nd_fd = -1;
                }
-               free(sndbuf);
-               free(rcvbuf);
-               sndbuf = NULL;
-               rcvbuf = NULL;
        }
 
        return n;
@@ -506,11 +447,11 @@ rtpref(struct ra *rap)
 }
 
 static void
-add_router(struct ra *router)
+add_router(struct ipv6_ctx *ctx, struct ra *router)
 {
        struct ra *rap;
 
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ctx->ra_routers, next) {
                if (router->iface->metric < rap->iface->metric ||
                    (router->iface->metric == rap->iface->metric &&
                    rtpref(router) > rtpref(rap)))
@@ -519,7 +460,7 @@ add_router(struct ra *router)
                        return;
                }
        }
-       TAILQ_INSERT_TAIL(&ipv6_routers, router, next);
+       TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
 }
 
 static int
@@ -565,7 +506,7 @@ ipv6nd_scriptrun(struct ra *rap)
 
        script_runreason(rap->iface, "ROUTERADVERT");
        if (hasdns)
-               hasdns = daemonise();
+               hasdns = daemonise(rap->iface->ctx);
 #if 0
        else if (options & DHCPCD_DAEMONISE &&
            !(options & DHCPCD_DAEMONISED) && new_data)
@@ -601,7 +542,7 @@ ipv6nd_dadcallback(void *arg)
        if (!wascompleted) {
                ifp = ap->iface;
 
-               TAILQ_FOREACH(rap, &ipv6_routers, next) {
+               TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
                        if (rap->iface != ifp)
                                continue;
                        wascompleted = 1;
@@ -629,7 +570,8 @@ ipv6nd_dadcallback(void *arg)
 }
 
 static void
-ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
+ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
+    struct icmp6_hdr *icp, ssize_t len)
 {
        ssize_t l, m, n, olen;
        struct nd_router_advert *nd_ra;
@@ -651,25 +593,26 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
        uint8_t new_rap, new_data;
 
        if ((size_t)len < sizeof(struct nd_router_advert)) {
-               syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom);
+               syslog(LOG_ERR, "IPv6 RA packet too short from %s", ctx->sfrom);
                return;
        }
 
-       if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
-               syslog(LOG_ERR, "RA from non local address %s", sfrom);
+       if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
+               syslog(LOG_ERR, "RA from non local address %s", ctx->sfrom);
                return;
        }
 
        if (ifp == NULL) {
 #ifdef DEBUG_RS
-               syslog(LOG_DEBUG, "RA for unexpected interface from %s", sfrom);
+               syslog(LOG_DEBUG, "RA for unexpected interface from %s",
+                   ctx->sfrom);
 #endif
                return;
        }
        if (!(ifp->options->options & DHCPCD_IPV6RS)) {
 #ifdef DEBUG_RS
                syslog(LOG_DEBUG, "%s: unexpected RA from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
 #endif
                return;
        }
@@ -678,14 +621,14 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
        if (ipv6_linklocal(ifp) == NULL) {
 #ifdef DEBUG_RS
                syslog(LOG_DEBUG, "%s: received RA from %s (no link-local)",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
 #endif
                return;
        }
 
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ctx->ra_routers, next) {
                if (ifp == rap->iface &&
-                   memcmp(rap->from.s6_addr, from.sin6_addr.s6_addr,
+                   memcmp(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr,
                    sizeof(rap->from.s6_addr)) == 0)
                        break;
        }
@@ -714,7 +657,7 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
                new_data = 0;
        if (new_data || ifp->options->options & DHCPCD_DEBUG)
                syslog(LOG_INFO, "%s: Router Advertisement from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
 
        if (rap == NULL) {
                rap = calloc(1, sizeof(*rap));
@@ -723,9 +666,9 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
                        return;
                }
                rap->iface = ifp;
-               memcpy(rap->from.s6_addr, from.sin6_addr.s6_addr,
+               memcpy(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr,
                    sizeof(rap->from.s6_addr));
-               strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
+               strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
                TAILQ_INIT(&rap->addrs);
                TAILQ_INIT(&rap->options);
                new_rap = 1;
@@ -765,7 +708,7 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
        lifetime = ~0U;
        for (olen = 0; len > 0; p += olen, len -= olen) {
                if ((size_t)len < sizeof(struct nd_opt_hdr)) {
-                       syslog(LOG_ERR, "%s: Short option", ifp->name);
+                       syslog(LOG_ERR, "%s: short option", ifp->name);
                        break;
                }
                ndo = (struct nd_opt_hdr *)p;
@@ -841,7 +784,7 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
                                            pi->nd_opt_pi_prefix_len);
                                        cbp = inet_ntop(AF_INET6,
                                            ap->addr.s6_addr,
-                                           ntopbuf, INET6_ADDRSTRLEN);
+                                           buf, sizeof(buf));
                                        if (cbp)
                                                snprintf(ap->saddr,
                                                    sizeof(ap->saddr),
@@ -1001,13 +944,13 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
        }
 
        if (new_rap)
-               add_router(rap);
-       if (options & DHCPCD_TEST) {
+               add_router(ifp->ctx->ipv6, rap);
+       if (ifp->ctx->options & DHCPCD_TEST) {
                script_runreason(ifp, "TEST");
                goto handle_flag;
        }
        ipv6nd_probeaddrs(&rap->addrs);
-       ipv6_buildroutes();
+       ipv6_buildroutes(ifp->ctx);
 
        /* We will get run by the expire function */
        if (rap->lifetime) {
@@ -1015,8 +958,8 @@ ipv6nd_handlera(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
                        return;
        }
 
-       eloop_timeout_delete(NULL, ifp);
-       eloop_timeout_delete(NULL, rap); /* reachable timer */
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
 
        /* If we're owning the RA then we need to try and ensure the
         * router is actually reachable */
@@ -1041,8 +984,8 @@ handle_flag:
                if (rap->lifetime && new_data)
                        syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
                            ifp->name);
-               if (options & DHCPCD_TEST) {
-                       eloop_exit(EXIT_SUCCESS);
+               if (ifp->ctx->options & DHCPCD_TEST) {
+                       eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
                        return;
                }
        }
@@ -1056,7 +999,7 @@ ipv6nd_has_ra(const struct interface *ifp)
 {
        const struct ra *rap;
 
-       TAILQ_FOREACH(rap, &ipv6_routers, next)
+       TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next)
                if (rap->iface == ifp)
                        return 1;
        return 0;
@@ -1076,7 +1019,7 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
 
        i = 0;
        l = 0;
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
                i++;
                if (rap->iface != ifp)
                        continue;
@@ -1174,12 +1117,14 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
 }
 
 void
-ipv6nd_handleifa(int cmd, const char *ifname,
+ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
     const struct in6_addr *addr, int flags)
 {
        struct ra *rap;
 
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       if (ctx->ipv6 == NULL)
+               return;
+       TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
                if (strcmp(rap->iface->name, ifname))
                        continue;
                ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
@@ -1200,7 +1145,7 @@ ipv6nd_expirera(void *arg)
        expired = 0;
        timerclear(&next);
 
-       TAILQ_FOREACH_SAFE(rap, &ipv6_routers, next, ran) {
+       TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
                if (rap->iface != ifp)
                        continue;
                lt.tv_sec = rap->lifetime;
@@ -1267,9 +1212,10 @@ ipv6nd_expirera(void *arg)
        }
 
        if (timerisset(&next))
-               eloop_timeout_add_tv(&next, ipv6nd_expirera, ifp);
+               eloop_timeout_add_tv(ifp->ctx->eloop,
+                   &next, ipv6nd_expirera, ifp);
        if (expired) {
-               ipv6_buildroutes();
+               ipv6_buildroutes(ifp->ctx);
                script_runreason(ifp, "ROUTERADVERT");
        }
 }
@@ -1281,12 +1227,12 @@ ipv6nd_drop(struct interface *ifp)
        int expired = 0;
        TAILQ_HEAD(rahead, ra) rtrs;
 
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
        TAILQ_INIT(&rtrs);
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
                if (rap->iface == ifp) {
                        rap->expired = expired = 1;
-                       TAILQ_REMOVE(&ipv6_routers, rap, next);
+                       TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next);
                        TAILQ_INSERT_TAIL(&rtrs, rap, next);
                }
        }
@@ -1295,7 +1241,7 @@ ipv6nd_drop(struct interface *ifp)
                        TAILQ_REMOVE(&rtrs, rap, next);
                        ipv6nd_drop_ra(rap);
                }
-               ipv6_buildroutes();
+               ipv6_buildroutes(ifp->ctx);
                if ((ifp->options->options &
                    (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
                    (DHCPCD_EXITING | DHCPCD_PERSISTENT))
@@ -1314,7 +1260,7 @@ ipv6nd_unreachable(void *arg)
        syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
            rap->iface->name, rap->sfrom);
        rap->expired = 1;
-       ipv6_buildroutes();
+       ipv6_buildroutes(rap->iface->ctx);
        script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
 
        /* We should still test if it's reachable or not so
@@ -1325,7 +1271,8 @@ ipv6nd_unreachable(void *arg)
                tv.tv_sec = REACHABLE_TIME;
                tv.tv_usec = 0;
        }
-       eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap);
+       eloop_timeout_add_tv(rap->iface->ctx->eloop,
+           &tv, ipv6nd_proberouter, rap);
 }
 
 #ifdef LISTEN_DAD
@@ -1333,9 +1280,9 @@ void
 ipv6nd_cancelprobeaddr(struct ipv6_addr *ap)
 {
 
-       eloop_timeout_delete(ipv6nd_probeaddr, ap);
+       eloop_timeout_delete(ap->iface->ctx->eloop, ipv6nd_probeaddr, ap);
        if (ap->dadcallback)
-               eloop_timeout_delete(ap->dadcallback, ap);
+               eloop_timeout_delete(ap->iface->ctx->eloop, ap->dadcallback,ap);
 }
 #endif
 
@@ -1372,8 +1319,10 @@ ipv6nd_probeaddr(void *arg)
                return;
        }
 
-       if (ipv6nd_naopen() == -1)
+       if (ipv6nd_open(ap->iface->ctx) == -1) {
+               syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
                return;
+       }
 
        ap->flags &= ~IPV6_AF_DADCOMPLETED;
 
@@ -1453,7 +1402,7 @@ ipv6nd_probeaddr(void *arg)
                    (MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
                timeradd(&tv, &rtv, &tv);
 
-               eloop_timeout_add_tv(&tv,
+               eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv,
                    ++(ap->nsprobes) < ap->iface->options->dadtransmits ?
                    ipv6nd_probeaddr : ap->dadcallback,
                    ap);
@@ -1476,7 +1425,8 @@ ipv6nd_probeaddr(void *arg)
                        timeradd(&tv, &rtv, &tv);
                        timeradd(&mtv, &tv, &mtv);
                }
-               eloop_timeout_add_tv(&mtv, ap->dadcallback, ap);
+               eloop_timeout_add_tv(ap->iface->ctx->eloop,
+                   &mtv, ap->dadcallback, ap);
        }
 #endif
 #endif /* IPV6_SEND_DAD */
@@ -1502,8 +1452,8 @@ ipv6nd_probeaddrs(struct ipv6_addrhead *addrs)
                                        syslog(LOG_ERR, "del_address6 %m");
                        }
                        if (ap->dadcallback)
-                               eloop_q_timeout_delete(0, NULL,
-                                   ap->dadcallback);
+                               eloop_q_timeout_delete(ap->iface->ctx->eloop,
+                                   0, NULL, ap->dadcallback);
                        free(ap);
                } else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) {
                        ipv6nd_probeaddr(ap);
@@ -1526,9 +1476,12 @@ ipv6nd_proberouter(void *arg)
        struct in6_pktinfo pi;
        int hoplimit = HOPLIMIT;
        struct timeval tv, rtv;
+       struct ipv6_ctx *ctx;
 
-       if (ipv6nd_naopen() == -1)
+       if (ipv6nd_open(rap->iface->ctx) == -1) {
+               syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
                return;
+       }
 
        if (!rap->ns) {
                rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
@@ -1557,12 +1510,13 @@ ipv6nd_proberouter(void *arg)
        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;
+       ctx = rap->iface->ctx->ipv6;
+       ctx->sndhdr.msg_name = (caddr_t)&dst;
+       ctx->sndhdr.msg_iov[0].iov_base = rap->ns;
+       ctx->sndhdr.msg_iov[0].iov_len = rap->nslen;
 
        /* Set the outbound interface */
-       cm = CMSG_FIRSTHDR(&sndhdr);
+       cm = CMSG_FIRSTHDR(&ctx->sndhdr);
        cm->cmsg_level = IPPROTO_IPV6;
        cm->cmsg_type = IPV6_PKTINFO;
        cm->cmsg_len = CMSG_LEN(sizeof(pi));
@@ -1571,7 +1525,7 @@ ipv6nd_proberouter(void *arg)
        memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
 
        /* Hop limit */
-       cm = CMSG_NXTHDR(&sndhdr, cm);
+       cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
        cm->cmsg_level = IPPROTO_IPV6;
        cm->cmsg_type = IPV6_HOPLIMIT;
        cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
@@ -1581,7 +1535,7 @@ ipv6nd_proberouter(void *arg)
        syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
            rap->iface->name, rap->sfrom);
 #endif
-       if (sendmsg(sock, &sndhdr, 0) == -1) {
+       if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
                syslog(LOG_ERR, "%s: %s: sendmsg: %m",
                    rap->iface->name, __func__);
                return;
@@ -1593,24 +1547,25 @@ ipv6nd_proberouter(void *arg)
        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);
+       eloop_timeout_add_tv(rap->iface->ctx->eloop,
+           &tv, ipv6nd_proberouter, rap);
 
        if (rap->nsprobes++ == 0)
-               eloop_timeout_add_sec(DELAY_FIRST_PROBE_TIME,
-                   ipv6nd_unreachable, rap);
+               eloop_timeout_add_sec(rap->iface->ctx->eloop,
+                   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);
+       eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap);
+       eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap);
 }
 
-/* ARGSUSED */
 static void
-ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
+ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
+    struct icmp6_hdr *icp, ssize_t len)
 {
        struct nd_neighbor_advert *nd_na;
        struct ra *rap;
@@ -1626,13 +1581,14 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
 #endif
 
        if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
-               syslog(LOG_ERR, "IPv6 NA packet too short from %s", sfrom);
+               syslog(LOG_ERR, "IPv6 NA packet too short from %s", ctx->sfrom);
                return;
        }
 
        if (ifp == NULL) {
 #ifdef DEBUG_NS
-               syslog(LOG_DEBUG, "NA for unexpected interface from %s", sfrom);
+               syslog(LOG_DEBUG, "NA for unexpected interface from %s",
+                   ctx->sfrom);
 #endif
                return;
        }
@@ -1643,14 +1599,14 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
 
        if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
                syslog(LOG_ERR, "%s: NA for multicast address from %s",
-                   ifp->name, sfrom);
+                   ifp->name, ctx->sfrom);
                return;
        }
 
 #ifdef DEBUG_NS
        found = 0;
 #endif
-       TAILQ_FOREACH(rap, &ipv6_routers, next) {
+       TAILQ_FOREACH(rap, ctx->ra_routers, next) {
                if (rap->iface != ifp)
                        continue;
                if (memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
@@ -1695,23 +1651,23 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
 #ifdef DEBUG_NS
                if (found == 0)
                        syslog(LOG_DEBUG, "%s: unexpected NA from %s",
-                           ifp->name, sfrom);
+                           ifp->name, ctx->sfrom);
 #endif
                return;
        }
 
 #ifdef DEBUG_NS
        syslog(LOG_DEBUG, "%s: %sNA from %s",
-           ifp->name, is_solicited ? "solicited " : "",  sfrom);
+           ifp->name, is_solicited ? "solicited " : "", ctx->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);
+                   ifp->name, ctx->sfrom);
                rap->expired = 1;
                ipv6nd_cancelproberouter(rap);
-               ipv6_buildroutes();
+               ipv6_buildroutes(ifp->ctx);
                script_runreason(ifp, "ROUTERADVERT");
                return;
        }
@@ -1720,8 +1676,8 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
                if (rap->expired) {
                        rap->expired = 0;
                        syslog(LOG_INFO, "%s: %s is reachable again",
-                               ifp->name, sfrom);
-                       ipv6_buildroutes();
+                           ifp->name, ctx->sfrom);
+                       ipv6_buildroutes(ifp->ctx);
                        script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
                }
                rap->nsprobes = 0;
@@ -1731,15 +1687,18 @@ ipv6nd_handlena(struct interface *ifp, struct icmp6_hdr *icp, ssize_t len)
                        tv.tv_sec = REACHABLE_TIME;
                        tv.tv_usec = 0;
                }
-               eloop_timeout_add_tv(&tv, ipv6nd_proberouter, rap);
-               eloop_timeout_delete(ipv6nd_unreachable, rap);
+               eloop_timeout_add_tv(rap->iface->ctx->eloop,
+                   &tv, ipv6nd_proberouter, rap);
+               eloop_timeout_delete(rap->iface->ctx->eloop,
+                   ipv6nd_unreachable, rap);
        }
 }
 
-/* ARGSUSED */
 static void
-ipv6nd_handledata(__unused void *arg)
+ipv6nd_handledata(void *arg)
 {
+       struct dhcpcd_ctx *dhcpcd_ctx;
+       struct ipv6_ctx *ctx;
        ssize_t len;
        struct cmsghdr *cm;
        int hoplimit;
@@ -1747,22 +1706,25 @@ ipv6nd_handledata(__unused void *arg)
        struct icmp6_hdr *icp;
        struct interface *ifp;
 
-       len = recvmsg(sock, &rcvhdr, 0);
+       dhcpcd_ctx = arg;
+       ctx = dhcpcd_ctx->ipv6;
+       len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
        if (len == -1) {
                syslog(LOG_ERR, "recvmsg: %m");
                return;
        }
-       sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
-           ntopbuf, INET6_ADDRSTRLEN);
+       ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
+           ctx->ntopbuf, INET6_ADDRSTRLEN);
        if ((size_t)len < sizeof(struct icmp6_hdr)) {
-               syslog(LOG_ERR, "IPv6 ICMP packet too short from %s", sfrom);
+               syslog(LOG_ERR, "IPv6 ICMP packet too short from %s",
+                   ctx->sfrom);
                return;
        }
 
        pkt.ipi6_ifindex = hoplimit = 0;
-       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
+       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
             cm;
-            cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
+            cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
        {
                if (cm->cmsg_level != IPPROTO_IPV6)
                        continue;
@@ -1780,30 +1742,30 @@ ipv6nd_handledata(__unused void *arg)
 
        if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
                syslog(LOG_ERR,
-                   "IPv6 RA did not contain index or hop limit from %s",
-                   sfrom);
+                   "IPv6 RA/NA did not contain index or hop limit from %s",
+                   ctx->sfrom);
                return;
        }
 
-       TAILQ_FOREACH(ifp, ifaces, next) {
+       TAILQ_FOREACH(ifp, dhcpcd_ctx->ifaces, next) {
                if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
                        break;
        }
 
-       icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
+       icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
        if (icp->icmp6_code == 0) {
                switch(icp->icmp6_type) {
                        case ND_NEIGHBOR_ADVERT:
-                               ipv6nd_handlena(ifp, icp, len);
+                               ipv6nd_handlena(ctx, ifp, icp, len);
                                return;
                        case ND_ROUTER_ADVERT:
-                               ipv6nd_handlera(ifp, icp, len);
+                               ipv6nd_handlera(ctx, ifp, icp, len);
                                return;
                }
        }
 
        syslog(LOG_ERR, "invalid IPv6 type %d or code %d from %s",
-           icp->icmp6_type, icp->icmp6_code, sfrom);
+           icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
 }
 
 int
@@ -1812,15 +1774,12 @@ ipv6nd_startrs(struct interface *ifp)
        struct rs_state *state;
 
        syslog(LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
-       if (sock == -1) {
-               if (ipv6nd_open() == -1) {
-                       syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
-                       return -1;
-               }
-               eloop_event_add(sock, ipv6nd_handledata, NULL);
+       if (ipv6nd_open(ifp->ctx) == -1) {
+               syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
+               return -1;
        }
 
-       eloop_timeout_delete(NULL, ifp);
+       eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
 
        state = RS_STATE(ifp);
        if (state == NULL) {
index f7ec4a58be09542fda232b16ad41216b16f6d2b7..cc66f65b03db25e9d14f2ebe0e7ee8335197a121 100644 (file)
--- a/ipv6nd.h
+++ b/ipv6nd.h
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -65,7 +65,7 @@ struct ra {
        int expired;
 };
 
-extern TAILQ_HEAD(rahead, ra) ipv6_routers;
+TAILQ_HEAD(ra_head, ra);
 
 struct rs_state {
        unsigned char *rs;
@@ -83,14 +83,15 @@ struct rs_state {
 #ifdef INET6
 int ipv6nd_startrs(struct interface *);
 ssize_t ipv6nd_env(char **, const char *, const struct interface *);
-int ipv6nd_addrexists(const struct ipv6_addr *);
+int ipv6nd_addrexists(struct dhcpcd_ctx *, 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_handleifa(struct dhcpcd_ctx *, int,
+    const char *, const struct in6_addr *, int);
 void ipv6nd_drop(struct interface *);
 
 void ipv6nd_probeaddr(void *);
diff --git a/net.c b/net.c
index c440b9241d01d5e3a51daa04dea99452028e6f4b..fba09ec851bc7fca1cfc5182da3d9e272f6d063d 100644 (file)
--- a/net.c
+++ b/net.c
 #include "ipv6nd.h"
 #include "net.h"
 
-static char hwaddr_buffer[(HWADDR_LEN * 3) + 1 + 1024];
-
 char *
-hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
+hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen, char *buf, size_t buflen)
 {
-       char *p = hwaddr_buffer;
+       char *p;
        size_t i;
 
+       if (buf == NULL) {
+               return NULL;
+       }
+
+       if (hwlen * 3 > buflen) {
+               errno = ENOBUFS;
+               return 0;
+       }
+
+       p = buf;
        for (i = 0; i < hwlen; i++) {
                if (i > 0)
                        *p ++= ':';
                p += snprintf(p, 3, "%.2x", hwaddr[i]);
        }
-
        *p ++= '\0';
-
-       return hwaddr_buffer;
+       return buf;
 }
 
 size_t
@@ -223,7 +229,7 @@ up_interface(struct interface *iface)
 }
 
 struct if_head *
-discover_interfaces(int argc, char * const *argv)
+discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
 {
        struct ifaddrs *ifaddrs, *ifa;
        char *p;
@@ -277,7 +283,7 @@ discover_interfaces(int argc, char * const *argv)
                }
 
                /* Ensure that the interface name has settled */
-               if (!dev_initialized(ifa->ifa_name))
+               if (!dev_initialized(ctx, ifa->ifa_name))
                        continue;
 
                /* It's possible for an interface to have >1 AF_LINK.
@@ -314,15 +320,15 @@ discover_interfaces(int argc, char * const *argv)
                        if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
                                continue;
                }
-               for (i = 0; i < ifdc; i++)
-                       if (!fnmatch(ifdv[i], p, 0))
+               for (i = 0; i < ctx->ifdc; i++)
+                       if (!fnmatch(ctx->ifdv[i], p, 0))
                                break;
-               if (i < ifdc)
+               if (i < ctx->ifdc)
                        continue;
-               for (i = 0; i < ifac; i++)
-                       if (!fnmatch(ifav[i], p, 0))
+               for (i = 0; i < ctx->ifac; i++)
+                       if (!fnmatch(ctx->ifav[i], p, 0))
                                break;
-               if (ifac && i == ifac)
+               if (ctx->ifac && i == ctx->ifac)
                        continue;
 
                if (if_vimaster(ifa->ifa_name) == 1) {
@@ -335,6 +341,7 @@ discover_interfaces(int argc, char * const *argv)
                ifp = calloc(1, sizeof(*ifp));
                if (ifp == NULL)
                        return NULL;
+               ifp->ctx = ctx;
                strlcpy(ifp->name, p, sizeof(ifp->name));
                ifp->flags = ifa->ifa_flags;
 
@@ -346,7 +353,7 @@ discover_interfaces(int argc, char * const *argv)
                   )
                {
                        if (up_interface(ifp) == 0)
-                               options |= DHCPCD_WAITUP;
+                               ctx->options |= DHCPCD_WAITUP;
                        else
                                syslog(LOG_ERR, "%s: up_interface: %m",
                                    ifp->name);
@@ -355,7 +362,7 @@ discover_interfaces(int argc, char * const *argv)
                sdl_type = 0;
                /* Don't allow loopback unless explicit */
                if (ifp->flags & IFF_LOOPBACK) {
-                       if (argc == 0 && ifac == 0) {
+                       if (argc == 0 && ctx->ifac == 0) {
                                free_interface(ifp);
                                continue;
                        }
@@ -421,7 +428,7 @@ discover_interfaces(int argc, char * const *argv)
                if (!(ifp->flags & IFF_POINTOPOINT) &&
                    ifp->family != ARPHRD_ETHER)
                {
-                       if (argc == 0 && ifac == 0) {
+                       if (argc == 0 && ctx->ifac == 0) {
                                free_interface(ifp);
                                continue;
                        }
@@ -482,7 +489,7 @@ discover_interfaces(int argc, char * const *argv)
                                    (void *)ifa->ifa_dstaddr;
                        else
                                dst = NULL;
-                       ipv4_handleifa(RTM_NEWADDR, ifs, ifa->ifa_name,
+                       ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
                                &addr->sin_addr,
                                &net->sin_addr,
                                dst ? &dst->sin_addr : NULL);
@@ -495,7 +502,7 @@ discover_interfaces(int argc, char * const *argv)
                        ifa_flags = in6_addr_flags(ifa->ifa_name,
                            &sin6->sin6_addr);
                        if (ifa_flags != -1)
-                               ipv6_handleifa(RTM_NEWADDR, ifs,
+                               ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
                                    ifa->ifa_name,
                                    &sin6->sin6_addr, ifa_flags);
                        break;
diff --git a/net.h b/net.h
index 3854fde5fb418ea2faf5ea4c2fa12c1831dc2cd6..2057f59c217de4edf8ffc111db1fbb3a55dca6e8 100644 (file)
--- a/net.h
+++ b/net.h
 # define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
 #endif
 
-char *hwaddr_ntoa(const unsigned char *, size_t);
+char *hwaddr_ntoa(const unsigned char *, size_t, char *, size_t);
 size_t hwaddr_aton(unsigned char *, const char *);
 
 int getifssid(const char *, char *);
 int if_vimaster(const char *);
-struct if_head *discover_interfaces(int, char * const *);
+struct if_head *discover_interfaces(struct dhcpcd_ctx *, int, char * const *);
 void free_interface(struct interface *);
 int do_mtu(const char *, short int);
 #define get_mtu(iface) do_mtu(iface, 0)
@@ -96,6 +96,6 @@ int if_conf(struct interface *);
 int if_init(struct interface *);
 
 int open_link_socket(void);
-int manage_link(int);
+int manage_link(struct dhcpcd_ctx *);
 int carrier_status(struct interface *);
 #endif
index fcc465a63552093bccba70f3ef89d136ba347025..ba44b68e2eeaffd6c0d265dc8014f08d2e348702 100644 (file)
@@ -90,10 +90,10 @@ inet6_sysctl(int code, int val, int action)
 
 static int kernel_ra_set;
 void
-restore_kernel_ra(void)
+restore_kernel_ra(struct dhcpcd_ctx *ctx)
 {
 
-       if (kernel_ra_set == 0 || options & DHCPCD_FORKED)
+       if (kernel_ra_set == 0 || ctx->options & DHCPCD_FORKED)
                return;
        syslog(LOG_INFO, "restoring Kernel IPv6 RA support");
        if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 1) == -1)
index 877e9887e27569d0d63ef61e96517c48a6a9137e..2b5e142f2228d2280d89088cd3f054136db74229 100644 (file)
@@ -74,11 +74,6 @@ static const char *mproc =
 #endif
        ;
 
-#ifdef INET6
-static char **restore;
-static ssize_t nrestore;
-#endif
-
 int
 hardware_platform(char *str, size_t len)
 {
@@ -139,30 +134,27 @@ write_path(const char *path, const char *val)
 static const char *prefix = "/proc/sys/net/ipv6/conf";
 
 void
-restore_kernel_ra(void)
+restore_kernel_ra(struct dhcpcd_ctx *ctx)
 {
        char path[256];
 
-       if (options & DHCPCD_FORKED)
-               return;
-
-       for (; nrestore > 0; nrestore--) {
-               if (!(options & DHCPCD_FORKED)) {
+       for (; ctx->ra_restore_len > 0; ctx->ra_restore_len--) {
+               if (!(ctx->options & DHCPCD_FORKED)) {
                        syslog(LOG_INFO, "%s: restoring Kernel IPv6 RA support",
-                           restore[nrestore - 1]);
+                           ctx->ra_restore[ctx->ra_restore_len - 1]);
                        snprintf(path, sizeof(path), "%s/%s/accept_ra",
-                           prefix, restore[nrestore - 1]);
+                           prefix, ctx->ra_restore[ctx->ra_restore_len - 1]);
                        if (write_path(path, "1") == -1 && errno != ENOENT)
                            syslog(LOG_ERR, "write_path: %s: %m", path);
                }
-               free(restore[nrestore - 1]);
+               free(ctx->ra_restore[ctx->ra_restore_len - 1]);
        }
-       free(restore);
-       restore = NULL;
+       free(ctx->ra_restore);
+       ctx->ra_restore = NULL;
 }
 
 int
-check_ipv6(const char *ifname, int own)
+check_ipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
 {
        int ra, i;
        char path[256], *p, **nrest;
@@ -192,24 +184,23 @@ check_ipv6(const char *ifname, int own)
                        syslog(LOG_ERR, "write_path: %s: %m", path);
                        return ra;
                }
-               for (i = 0; i < nrestore; i++)
-                       if (strcmp(restore[i], ifname) == 0)
+               for (i = 0; i < ctx->ra_restore_len; i++)
+                       if (strcmp(ctx->ra_restore[i], ifname) == 0)
                                break;
-               if (i == nrestore) {
+               if (i == ctx->ra_restore_len) {
                        p = strdup(ifname);
                        if (p == NULL) {
                                syslog(LOG_ERR, "%s: %m", __func__);
                                return ra;
                        }
-                       nrest = realloc(restore,
-                           (nrestore + 1) * sizeof(char *));
+                       nrest = realloc(ctx->ra_restore,
+                           (ctx->ra_restore_len + 1) * sizeof(char *));
                        if (nrest == NULL) {
                                syslog(LOG_ERR, "%s: %m", __func__);
                                return ra;
                        }
-                       restore = nrest;
-                       restore[nrestore++] = p;
-
+                       ctx->ra_restore = nrest;
+                       ctx->ra_restore[ctx->ra_restore_len++] = p;
                }
        }
 
index b79ec483c264bbadb33d1ab119a7c2d553fd3a00..8011b1beaac96fbafa03af8c0dd9d5b4a6b7a378 100644 (file)
 
 int hardware_platform(char *, size_t);
 #ifdef INET6
-int check_ipv6(const char *, int);
+int check_ipv6(struct dhcpcd_ctx *ctx, const char *, int);
 int ipv6_dadtransmits(const char *);
-void restore_kernel_ra(void);
+void restore_kernel_ra(struct dhcpcd_ctx *);
 #else
-#define check_ipv6(a, b) -1
+#define check_ipv6(a, b,c ) -1
 #define restore_kernel_ra(a)
 #endif
 
index 2de1e63473eb574de339bc941d686991f7107634..ec99c5fdcb7e0e11d2fc25728a5ac6a1ad3e05b6 100644 (file)
--- a/script.c
+++ b/script.c
@@ -77,7 +77,7 @@ if_printoptions(void)
 }
 
 static int
-exec_script(char *const *argv, char *const *env)
+exec_script(const sigset_t *sigs, char *const *argv, char *const *env)
 {
        pid_t pid;
        posix_spawnattr_t attr;
@@ -95,7 +95,7 @@ exec_script(char *const *argv, char *const *env)
        for (i = 0; i < handle_sigs[i]; i++)
                sigaddset(&defsigs, handle_sigs[i]);
        posix_spawnattr_setsigdefault(&attr, &defsigs);
-       posix_spawnattr_setsigmask(&attr, &dhcpcd_sigset);
+       posix_spawnattr_setsigmask(&attr, sigs);
        errno = 0;
        i = posix_spawn(&pid, argv[0], NULL, &attr, argv, env);
        if (i) {
@@ -228,7 +228,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
 
        /* When dumping the lease, we only want to report interface and
           reason - the other interface variables are meaningless */
-       if (options & DHCPCD_DUMPLEASE)
+       if (ifp->ctx->options & DHCPCD_DUMPLEASE)
                elen = 2;
        else
                elen = 10;
@@ -244,7 +244,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        e = strlen("reason") + strlen(reason) + 2;
        EMALLOC(1, e);
        snprintf(env[1], e, "reason=%s", reason);
-       if (options & DHCPCD_DUMPLEASE)
+       if (ifp->ctx->options & DHCPCD_DUMPLEASE)
                goto dumplease;
        e = 20;
        EMALLOC(2, e);
@@ -258,7 +258,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        EMALLOC(6, e);
        snprintf(env[6], e, "ifmtu=%d", get_mtu(ifp->name));
        l = e = strlen("interface_order=");
-       TAILQ_FOREACH(ifp2, ifaces, next) {
+       TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
                e += strlen(ifp2->name) + 1;
        }
        EMALLOC(7, e);
@@ -266,7 +266,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        strlcpy(p, "interface_order=", e);
        e -= l;
        p += l;
-       TAILQ_FOREACH(ifp2, ifaces, next) {
+       TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
                l = strlcpy(p, ifp2->name, e);
                p += l;
                e -= l;
@@ -555,7 +555,7 @@ script_runreason(const struct interface *ifp, const char *reason)
        }
        env[++elen] = NULL;
 
-       pid = exec_script(argv, env);
+       pid = exec_script(&ifp->ctx->sigset, argv, env);
        if (pid == -1)
                syslog(LOG_ERR, "%s: %s: %m", __func__, argv[0]);
        else if (pid != 0) {
@@ -579,7 +579,7 @@ script_runreason(const struct interface *ifp, const char *reason)
 
        /* Send to our listeners */
        bigenv = NULL;
-       for (fd = control_fds; fd != NULL; fd = fd->next) {
+       for (fd = ifp->ctx->control_fds; fd != NULL; fd = fd->next) {
                if (fd->listener) {
                        if (bigenv == NULL) {
                                elen = arraytostr((const char *const *)env,