signal handling.
This allows dhcpcd to work better in a threaded environment such as rtems.
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
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;
{
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);
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;
}
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);
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,
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)) {
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;
}
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) {
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",
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;
}
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;
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 {
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);
#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];
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);
}
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);
}
/*
* 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)
{
uint8_t protocol;
uint8_t algorithm;
uint8_t rdm;
+ uint64_t last_replay;
+ uint8_t last_replay_set;
struct token_head tokens;
};
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
# 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.
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
}
#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);
}
#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 *);
(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);
*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;
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)
}
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));
}
int
-control_start(struct control_ctx *ctx)
+control_start(struct dhcpcd_ctx *ctx)
{
struct sockaddr_un sun;
int len;
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;
memcpy(p, argv[i], len);
p += len;
}
- return write(ctx->fd, buffer, p - buffer);
+ return write(ctx->control_fd, buffer, p - buffer);
}
#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
#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);
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) {
if (d->d_name[0] == '.')
continue;
- r = dev_start2(d->d_name);
+ r = dev_start2(ctx, d->d_name);
if (r != -1)
break;
}
}
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;
}
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
}
static int
-udev_handle_device(void)
+udev_handle_device(void *ctx)
{
struct udev_device *device;
const char *subsystem, *ifname, *action;
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);
#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)
{
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;
}
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)
{
{
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++)
/* Report error? */
continue;
}
- n += dhcp_envoption(
+ n += dhcp_envoption(ctx,
env == NULL ? NULL : &env[n], pfx,
ifname,
eopt->type & OPTION ? oopt : eopt,
/*
* 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 <stdint.h>
#include "common.h"
+#include "dhcpcd.h"
/* Max MTU - defines dhcp option length */
#define MTU_MAX 1500
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);
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 *);
#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
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;
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);
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;
}
*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;
}
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));
}
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));
}
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)
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;
/* 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 ";
}
}
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) {
/* 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) {
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;
}
if (type == DHCP_DISCOVER &&
- !(options & DHCPCD_TEST) &&
+ !(iface->ctx->options & DHCPCD_TEST) &&
has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT))
{
/* RFC 4039 Section 3 */
}
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) {
*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;
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;
}
}
/* 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,
}
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;
}
}
- 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;
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)
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;
{
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;
* 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));
/* 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))
/* 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);
}
}
{
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;
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;
}
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;
}
}
static int
-dhcp_openudp(struct interface *ifp)
+dhcp_openudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
{
int s;
struct sockaddr_in sin;
if (ifp)
state->udp_fd = s;
else
- udp_fd = s;
+ ctx->udp_fd = s;
return 0;
eexit:
/* Ensure sockets are open. */
if (dhcp_open(iface) == -1) {
- if (!(options & DHCPCD_TEST))
+ if (!(iface->ctx->options & DHCPCD_TEST))
dhcp_drop(iface, "FAIL");
return;
}
* 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;
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;
}
}
/* 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
/* 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;
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)",
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);
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);
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),
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) {
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;
}
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);
}
}
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 {
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);
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 &&
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));
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,
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,
/* 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;
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;
/* 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 {
/* 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;
/* 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. */
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
}
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)
* 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;
"%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",
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);
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
{
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;
}
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 &&
(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;
}
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;
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));
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);
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;
}
}
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) {
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);
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:
/* 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);
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) {
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;
#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 *,
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 *);
/* 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;
{ 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;
};
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)
{
}
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;
} 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;
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);
}
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)))
}
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);
}
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);
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);
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);
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) &&
if (state) {
ipv6_freedrop_addrs(&state->addrs, drop, ifd);
if (drop)
- ipv6_buildroutes();
+ ipv6_buildroutes(ifp->ctx);
}
}
{
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);
}
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;
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;
(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;
/* 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;
}
}
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));
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");
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);
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;
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",
/* 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);
}
{
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;
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
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);
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) {
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 *
}
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;
}
syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
ifp->name);
script_runreason(ifp, state->reason);
- daemonise();
+ daemonise(ifp->ctx);
}
}
}
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);
}
}
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)
{
}
static uint32_t
-dhcp6_findsla(void)
+dhcp6_findsla(const struct dhcpcd_ctx *ctx)
{
uint32_t sla;
const struct interface *ifp;
/* 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;
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);
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) {
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",
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;
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;
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;
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);
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] ||
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;
}
}
{
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) {
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;
}
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 */
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,
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:
ifp->name);
return;
}
- eloop_timeout_delete(dhcp6_sendinform, ifp);
+ eloop_timeout_delete(ifp->ctx->eloop,
+ dhcp6_sendinform, ifp);
dhcp6_startinform(ifp);
break;
default:
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;
}
}
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;
state->recv_len = 0;
}
- if (options & DHCPCD_TEST)
+ if (ifp->ctx->options & DHCPCD_TEST)
script_runreason(ifp, "TEST");
else {
if (state->state == DH6S_INFORM)
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);
"%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;
}
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);
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;
}
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));
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
/* 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;
+ }
}
}
}
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;
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);
} 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),
((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()
#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,
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)
}
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
/* Returns the pid of the child, otherwise 0. */
pid_t
-daemonise(void)
+daemonise(struct dhcpcd_ctx *ctx)
{
#ifdef THERE_IS_NO_FORK
errno = ENOSYS;
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) {
/* 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;
}
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
/* 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;
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;
{
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;
/* 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);
}
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,
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;
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,
{
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);
}
}
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");
}
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) {
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);
}
/* 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;
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);
}
}
}
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;
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);
}
}
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);
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 {
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) {
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",
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:
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) {
stop_interface(ifp);
}
}
- eloop_exit(EXIT_FAILURE);
+ eloop_exit(ctx->eloop, EXIT_FAILURE);
}
static void
* 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;
}
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");
} 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++;
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))
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);
}
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;
return 0;
}
- reconf_reboot(do_reboot, argc, argv, optind);
+ reconf_reboot(ctx, do_reboot, argc, argv, optind);
return 0;
}
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));
}
}
- 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)
{
family = AF_INET6;
break;
case 'f':
- cffile = optarg;
+ ctx.cffile = optarg;
break;
case 'g':
sig = SIGUSR1;
}
}
- 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();
#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__);
}
}
- 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;
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;
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");
}
}
- if (!(options & DHCPCD_TEST)) {
+ if (!(ctx.options & DHCPCD_TEST)) {
if ((pid = read_pid(pidfile)) > 0 &&
kill(pid, 0) == 0)
{
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");
}
}
#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:
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;
}
/*
* 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
#define IF_DATA_MAX 5
struct interface {
+ struct dhcpcd_ctx *ctx;
TAILQ_ENTRY(interface) next;
char name[IF_NAMESIZE];
unsigned int index;
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 *);
#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)
{
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
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;
}
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) {
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;
}
# define DUID_LEN 128 + 2
#endif
-extern unsigned char *duid;
-extern size_t duid_len;
-
size_t duid_init(const struct interface *);
#endif
#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;
}
/* 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) {
}
/* 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 */
* 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);
}
/* 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) {
/* 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;
}
* 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)
{
}
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);
/* 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;
/* 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
}
}
- /* 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;
}
* 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
#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];
#endif
for (;;) {
- bytes = read(fd, msg, sizeof(msg));
+ bytes = read(ctx->link_fd, msg, sizeof(msg));
if (bytes == -1) {
if (errno == EAGAIN)
return 0;
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;
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 &
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
#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;
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;
break;
} else
ifa_flags = 0;
- ipv6_handleifa(rtm->rtm_type, NULL,
+ ipv6_handleifa(ctx, rtm->rtm_type, NULL,
ifname, &ia6, ifa_flags);
break;
#endif
}
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;
NLMSG_OK(nlm, (size_t)bytes);
nlm = NLMSG_NEXT(nlm, bytes))
{
- r = callback(nlm);
+ r = callback(ctx, nlm);
if (r != 0)
goto eexit;
}
}
static int
-err_netlink(struct nlmsghdr *nlm)
+err_netlink(__unused struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
{
struct nlmsgerr *err;
int l;
}
static int
-link_route(struct nlmsghdr *nlm)
+link_route(struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
{
int len, idx, metric;
struct rtattr *rta;
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);
if (metric == rt.iface->metric) {
#ifdef INET
inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
- ipv4_routedeleted(&rt);
+ ipv4_routedeleted(ctx, &rt);
#endif
}
}
}
static int
-link_addr(struct nlmsghdr *nlm)
+link_addr(struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
{
int len;
struct rtattr *rta;
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);
}
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
}
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
}
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;
}
}
}
static int
-link_netlink(struct nlmsghdr *nlm)
+link_netlink(struct dhcpcd_ctx *ctx, struct nlmsghdr *nlm)
{
int len;
struct rtattr *rta, *hwaddr;
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;
}
if (nlm->nlmsg_type == RTM_DELLINK) {
- handle_interface(-1, ifn);
+ handle_interface(ctx, -1, ifn);
return 1;
}
* 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;
}
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;
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);
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
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;
}
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
#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
#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'},
#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;
#endif
#ifdef INET
- *d = dhcp_opts;
- *dl = dhcp_opts_len;
+ *d = ctx->dhcp_opts;
+ *dl = ctx->dhcp_opts_len;
#else
*d = NULL;
*dl = 0;
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)
{
}
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;
}
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);
}
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;
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 ||
}
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)
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;
}
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"
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;
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");
/* 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 */
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);
}
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;
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;
}
* 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;
}
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;
size_t i;
struct dhcp_opt *opt;
#endif
+ struct dhcp_opt *ldop, *edop;
/* Seed our default options */
ifo = calloc(1, sizeof(*ifo));
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) {
*(p - 1) != '\\')
*p-- = '\0';
}
- parse_config_line(NULL, ifo, option, line);
+ parse_config_line(ctx, NULL, ifo, option, line,
+ &ldop, &edop);
}
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;
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;
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)
}
if (skip)
continue;
- parse_config_line(ifname, ifo, option, line);
+ parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
}
fclose(fp);
free(buf);
}
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;
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;
}
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 *);
/*
* 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
/* 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);
if (ift == NULL)
TAILQ_INSERT_TAIL(&sorted, ifp, next);
}
- TAILQ_CONCAT(ifaces, &sorted, next);
+ TAILQ_CONCAT(ctx->ifaces, &sorted, next);
}
#include "dhcpcd.h"
-void sort_interfaces(void);
+void sort_interfaces(struct dhcpcd_ctx *);
#endif
#undef IPV4_LOOPBACK_ROUTE
#endif
-static struct rt_head *routes;
-
int
inet_ntocidr(struct in_addr address)
{
}
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) {
}
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;
}
/* 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;
}
}
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;
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;
}
void
-ipv4_buildroutes(void)
+ipv4_buildroutes(struct dhcpcd_ctx *ctx)
{
struct rt_head *nrs, *dnr;
struct rt *or, *rt, *rtn;
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;
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 ||
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)
}
/* 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
/* 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;
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);
/* 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)
}
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)
{
struct ipv4_addr *ap;
if (ifs == NULL)
- ifs = ifaces;
+ ifs = ctx->ifaces;
if (ifs == NULL)
return;
if (addr->s_addr == INADDR_ANY)
}
free(state);
}
- } else {
- ipv4_freeroutes(routes);
- routes = NULL;
}
}
+
+void
+ipv4_ctxfree(struct dhcpcd_ctx *ctx)
+{
+
+ ipv4_freeroutes(ctx->ipv4_routes);
+}
/*
* 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
((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 *,
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
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) {
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);
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);
}
}
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
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))
}
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;
}
if (ifs == NULL)
- ifs = ifaces;
+ ifs = ctx->ifaces;
if (ifs == NULL) {
errno = ESRCH;
return;
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 */
{
struct ipv6_state *state;
struct ipv6_addr_l *ap;
- struct rt6 *rt;
if (ifp) {
ipv6_free_ll_callbacks(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)
}
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;
}
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
/* 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);
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) {
}
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);
}
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;
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
/* 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
/* 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) {
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) ||
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)
/* 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 &&
free(rt);
}
- free(routes);
- routes = nrs;
+ free(ctx->ipv6->routes);
+ ctx->ipv6->routes = nrs;
}
/*
* 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
int metric;
unsigned int mtu;
};
-TAILQ_HEAD(rt6head, rt6);
+TAILQ_HEAD(rt6_head, rt6);
struct ipv6_addr_l {
TAILQ_ENTRY(ipv6_addr_l) next;
#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);
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);
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)
#define ipv6_init() -1
#define ipv6_free_ll_callbacks(a)
#define ipv6_free(a)
+#define ipv6_ctxfree(a)
#endif
#endif
#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"
//#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);
/*
#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;
} 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;
}
ipv6nd_sendrsprobe(void *arg)
{
struct interface *ifp = arg;
+ struct ipv6_ctx *ctx;
struct rs_state *state;
struct sockaddr_in6 dst;
struct cmsghdr *cm;
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));
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);
}
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);
}
}
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 &
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);
{
struct rs_state *state;
struct ra *rap, *ran;
+ struct dhcpcd_ctx *ctx;
ssize_t n;
state = RS_STATE(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++;
/* 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;
}
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)))
return;
}
}
- TAILQ_INSERT_TAIL(&ipv6_routers, router, next);
+ TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
}
static int
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)
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;
}
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;
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;
}
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;
}
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));
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;
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;
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),
}
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) {
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 */
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;
}
}
{
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;
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;
}
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);
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;
}
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");
}
}
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);
}
}
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))
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
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
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
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;
(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);
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 */
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);
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);
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));
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));
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;
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;
#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;
}
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,
#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;
}
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;
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;
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;
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
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) {
/*
* 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
int expired;
};
-extern TAILQ_HEAD(rahead, ra) ipv6_routers;
+TAILQ_HEAD(ra_head, ra);
struct rs_state {
unsigned char *rs;
#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 *);
#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
}
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;
}
/* 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.
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) {
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;
)
{
if (up_interface(ifp) == 0)
- options |= DHCPCD_WAITUP;
+ ctx->options |= DHCPCD_WAITUP;
else
syslog(LOG_ERR, "%s: up_interface: %m",
ifp->name);
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;
}
if (!(ifp->flags & IFF_POINTOPOINT) &&
ifp->family != ARPHRD_ETHER)
{
- if (argc == 0 && ifac == 0) {
+ if (argc == 0 && ctx->ifac == 0) {
free_interface(ifp);
continue;
}
(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);
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;
# 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)
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
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)
#endif
;
-#ifdef INET6
-static char **restore;
-static ssize_t nrestore;
-#endif
-
int
hardware_platform(char *str, size_t len)
{
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;
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;
}
}
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
}
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;
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) {
/* 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;
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);
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);
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;
}
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) {
/* 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,