aboutsummaryrefslogtreecommitdiffstats
path: root/configure.c
diff options
context:
space:
mode:
Diffstat (limited to 'configure.c')
-rw-r--r--configure.c140
1 files changed, 99 insertions, 41 deletions
diff --git a/configure.c b/configure.c
index e64dd4e..fe89532 100644
--- a/configure.c
+++ b/configure.c
@@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +46,7 @@
#include "dhcp.h"
#include "if-options.h"
#include "if-pref.h"
+#include "ipv6rs.h"
#include "net.h"
#include "signals.h"
@@ -63,7 +64,6 @@
static struct rt *routes;
-
static int
exec_script(char *const *argv, char *const *env)
{
@@ -163,23 +163,39 @@ arraytostr(const char *const *argv, char **s)
}
static ssize_t
-make_env(const struct interface *iface, char ***argv)
+make_env(const struct interface *iface, const char *reason, char ***argv)
{
char **env, *p;
ssize_t e, elen, l;
const struct if_options *ifo = iface->state->options;
const struct interface *ifp;
+ int dhcp, ra;
+
+ dhcp = ra = 0;
+ if (strcmp(reason, "ROUTERADVERT") == 0)
+ ra = 1;
+ else
+ dhcp = 1;
+
+ /* When dumping the lease, we only want to report interface and
+ reason - the other interface variables are meaningless */
+ if (options & DHCPCD_DUMPLEASE)
+ elen = 2;
+ else
+ elen = 10;
/* Make our env */
- elen = 8;
env = xmalloc(sizeof(char *) * (elen + 1));
e = strlen("interface") + strlen(iface->name) + 2;
env[0] = xmalloc(e);
snprintf(env[0], e, "interface=%s", iface->name);
- e = strlen("reason") + strlen(iface->state->reason) + 2;
+ e = strlen("reason") + strlen(reason) + 2;
env[1] = xmalloc(e);
- snprintf(env[1], e, "reason=%s", iface->state->reason);
- e = 20;
+ snprintf(env[1], e, "reason=%s", reason);
+ if (options & DHCPCD_DUMPLEASE)
+ goto dumplease;
+
+ e = 20;
env[2] = xmalloc(e);
snprintf(env[2], e, "pid=%d", getpid());
env[3] = xmalloc(e);
@@ -205,6 +221,13 @@ make_env(const struct interface *iface, char ***argv)
e--;
}
*--p = '\0';
+ if ((dhcp && iface->state->new) || (ra && iface->ras)) {
+ env[8] = strdup("if_up=true");
+ env[9] = strdup("if_down=false");
+ } else {
+ env[8] = strdup("if_up=false");
+ env[9] = strdup("if_down=true");
+ }
if (*iface->state->profile) {
e = strlen("profile=") + strlen(iface->state->profile) + 2;
env[elen] = xmalloc(e);
@@ -227,7 +250,7 @@ make_env(const struct interface *iface, char ***argv)
snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
}
}
- if (iface->state->old) {
+ if (dhcp && iface->state->old) {
e = configure_env(NULL, NULL, iface->state->old, ifo);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
@@ -237,7 +260,9 @@ make_env(const struct interface *iface, char ***argv)
append_config(&env, &elen, "old",
(const char *const *)ifo->config);
}
- if (iface->state->new) {
+
+dumplease:
+ if (dhcp && iface->state->new) {
e = configure_env(NULL, NULL, iface->state->new, ifo);
if (e > 0) {
env = xrealloc(env, sizeof(char *) * (elen + e + 1));
@@ -247,6 +272,13 @@ make_env(const struct interface *iface, char ***argv)
append_config(&env, &elen, "new",
(const char *const *)ifo->config);
}
+ if (ra) {
+ e = ipv6rs_env(NULL, NULL, iface);
+ if (e > 0) {
+ env = xrealloc(env, sizeof(char *) * (elen + e + 1));
+ elen += ipv6rs_env(env + elen, NULL, iface);
+ }
+ }
/* Add our base environment */
if (ifo->environ) {
@@ -267,8 +299,8 @@ make_env(const struct interface *iface, char ***argv)
return elen;
}
-int
-send_interface(int fd, const struct interface *iface)
+static int
+send_interface1(int fd, const struct interface *iface, const char *reason)
{
char **env, **ep, *s;
ssize_t elen;
@@ -276,7 +308,7 @@ send_interface(int fd, const struct interface *iface)
int retval;
retval = 0;
- make_env(iface, &env);
+ make_env(iface, reason, &env);
elen = arraytostr((const char *const *)env, &s);
iov[0].iov_base = &elen;
iov[0].iov_len = sizeof(ssize_t);
@@ -292,7 +324,20 @@ send_interface(int fd, const struct interface *iface)
}
int
-run_script(const struct interface *iface)
+send_interface(int fd, const struct interface *iface)
+{
+ int retval = 0;
+ if (send_interface1(fd, iface, iface->state->reason) == -1)
+ retval = -1;
+ if (iface->ras) {
+ if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
+ retval = -1;
+ }
+ return retval;
+}
+
+int
+run_script_reason(const struct interface *iface, const char *reason)
{
char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
char **env = NULL, **ep;
@@ -303,11 +348,18 @@ run_script(const struct interface *iface)
const struct fd_list *fd;
struct iovec iov[2];
+ if (iface->state->options->script == NULL ||
+ iface->state->options->script[0] == '\0' ||
+ strcmp(iface->state->options->script, "/dev/null") == 0)
+ return 0;
+
+ if (reason == NULL)
+ reason = iface->state->reason;
syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
- iface->name, argv[0], iface->state->reason);
+ iface->name, argv[0], reason);
/* Make our env */
- elen = make_env(iface, &env);
+ elen = make_env(iface, reason, &env);
env = xrealloc(env, sizeof(char *) * (elen + 2));
/* Add path to it */
path = getenv("PATH");
@@ -383,9 +435,10 @@ find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
}
static void
-desc_route(const char *cmd, const struct rt *rt, const char *ifname)
+desc_route(const char *cmd, const struct rt *rt)
{
char addr[sizeof("000.000.000.000") + 1];
+ const char *ifname = rt->iface->name;
strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
if (rt->gate.s_addr == INADDR_ANY)
@@ -413,7 +466,7 @@ route_deleted(const struct rt *rt)
f = find_route(routes, rt, &l, NULL);
if (f == NULL)
return 0;
- desc_route("removing", f, f->iface->name);
+ desc_route("removing", f);
if (l)
l->next = f->next;
else
@@ -423,61 +476,60 @@ route_deleted(const struct rt *rt)
}
static int
-n_route(struct rt *rt, const struct interface *iface)
+n_route(struct rt *rt)
{
/* Don't set default routes if not asked to */
if (rt->dest.s_addr == 0 &&
rt->net.s_addr == 0 &&
- !(iface->state->options->options & DHCPCD_GATEWAY))
+ !(rt->iface->state->options->options & DHCPCD_GATEWAY))
return -1;
- desc_route("adding", rt, iface->name);
- if (!add_route(iface, &rt->dest, &rt->net, &rt->gate, iface->metric))
+ desc_route("adding", rt);
+ if (!add_route(rt))
return 0;
if (errno == EEXIST) {
/* Pretend we added the subnet route */
- if (rt->dest.s_addr == (iface->addr.s_addr & iface->net.s_addr) &&
- rt->net.s_addr == iface->net.s_addr &&
+ if (rt->dest.s_addr ==
+ (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
+ rt->net.s_addr == rt->iface->net.s_addr &&
rt->gate.s_addr == 0)
return 0;
else
return -1;
}
- syslog(LOG_ERR, "%s: add_route: %m", iface->name);
+ syslog(LOG_ERR, "%s: add_route: %m", rt->iface->name);
return -1;
}
static int
-c_route(struct rt *ort, struct rt *nrt, const struct interface *iface)
+c_route(struct rt *ort, struct rt *nrt)
{
/* Don't set default routes if not asked to */
if (nrt->dest.s_addr == 0 &&
nrt->net.s_addr == 0 &&
- !(iface->state->options->options & DHCPCD_GATEWAY))
+ !(nrt->iface->state->options->options & DHCPCD_GATEWAY))
return -1;
- desc_route("changing", nrt, iface->name);
+ desc_route("changing", nrt);
/* We delete and add the route so that we can change metric.
* This also has the nice side effect of flushing ARP entries so
* we don't have to do that manually. */
- del_route(ort->iface, &ort->dest, &ort->net, &ort->gate,
- ort->iface->metric);
- if (!add_route(iface, &nrt->dest, &nrt->net, &nrt->gate,
- iface->metric))
+ del_route(ort);
+ if (!add_route(nrt))
return 0;
- syslog(LOG_ERR, "%s: add_route: %m", iface->name);
+ syslog(LOG_ERR, "%s: add_route: %m", nrt->iface->name);
return -1;
}
static int
-d_route(struct rt *rt, const struct interface *iface, int metric)
+d_route(struct rt *rt)
{
int retval;
- desc_route("deleting", rt, iface->name);
- retval = del_route(iface, &rt->dest, &rt->net, &rt->gate, metric);
+ desc_route("deleting", rt);
+ retval = del_route(rt);
if (retval != 0 && errno != ENOENT && errno != ESRCH)
- syslog(LOG_ERR,"%s: del_route: %m", iface->name);
+ syslog(LOG_ERR,"%s: del_route: %m", rt->iface->name);
return retval;
}
@@ -652,15 +704,19 @@ build_routes(void)
dnr = add_destination_route(dnr, ifp);
for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
rt->iface = ifp;
+ rt->metric = ifp->metric;
/* Is this route already in our table? */
if ((find_route(nrs, rt, NULL, NULL)) != NULL)
continue;
+ rt->src.s_addr = ifp->addr.s_addr;
/* Do we already manage it? */
if ((or = find_route(routes, rt, &rtl, NULL))) {
if (or->iface != ifp ||
- rt->gate.s_addr != or->gate.s_addr)
+ or->src.s_addr != ifp->addr.s_addr ||
+ rt->gate.s_addr != or->gate.s_addr ||
+ rt->metric != or->metric)
{
- if (c_route(or, rt, ifp) != 0)
+ if (c_route(or, rt) != 0)
continue;
}
if (rtl != NULL)
@@ -669,7 +725,7 @@ build_routes(void)
routes = or->next;
free(or);
} else {
- if (n_route(rt, ifp) != 0)
+ if (n_route(rt) != 0)
continue;
}
if (dnr == rt)
@@ -678,6 +734,7 @@ build_routes(void)
lrt->next = rtn;
rt->next = nrs;
nrs = rt;
+ rt = lrt; /* When we loop this makes lrt correct */
}
free_routes(dnr);
}
@@ -685,7 +742,7 @@ build_routes(void)
/* Remove old routes we used to manage */
for (rt = routes; rt; rt = rt->next) {
if (find_route(nrs, rt, NULL, NULL) == NULL)
- d_route(rt, rt->iface, rt->iface->metric);
+ d_route(rt);
}
free_routes(routes);
@@ -766,8 +823,9 @@ configure(struct interface *iface)
rt = get_subnet_route(dhcp);
if (rt != NULL) {
rt->iface = iface;
+ rt->metric = 0;
if (!find_route(routes, rt, NULL, NULL))
- del_route(iface, &rt->dest, &rt->net, &rt->gate, 0);
+ del_route(rt);
free(rt);
}