summaryrefslogtreecommitdiffstats
path: root/dhcpcd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2008-09-03 16:49:28 +0000
committerRoy Marples <roy@marples.name>2008-09-03 16:49:28 +0000
commitf43e585355e50bd2e7021380db6fc792662f76be (patch)
treed81565b32d67516b6ae178bcdbff09bda3251b45 /dhcpcd.c
parentf0c98483e7369f2df38edc352433239fa24f6a2f (diff)
downloaddhcpcd-f43e585355e50bd2e7021380db6fc792662f76be.tar.xz
Add a control socket so that interfaces can be dynamically re-set.
This requires the event loop argument being changed to void * so we can send arguments other than an interface.
Diffstat (limited to 'dhcpcd.c')
-rw-r--r--dhcpcd.c254
1 files changed, 206 insertions, 48 deletions
diff --git a/dhcpcd.c b/dhcpcd.c
index 96d8cf70..c84164eb 100644
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -50,6 +50,7 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
#include "config.h"
#include "common.h"
#include "configure.h"
+#include "control.h"
#include "dhcpcd.h"
#include "dhcpf.h"
#include "duid.h"
@@ -63,13 +64,13 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
/* We should define a maximum for the NAK exponential backoff */
#define NAKOFF_MAX 60
+int master = 0;
int pidfd = -1;
static int linkfd = -1;
static char cffile[PATH_MAX];
static char pidfile[PATH_MAX] = { '\0' };
static struct interface *ifaces = NULL;
-
struct dhcp_op {
uint8_t value;
const char *name;
@@ -140,13 +141,18 @@ cleanup(void)
if (linkfd != -1)
close(linkfd);
if (pidfd > -1) {
+ if (master) {
+ if (stop_control() == -1)
+ logger(LOG_ERR, "stop_control: %s",
+ strerror(errno));
+ }
close(pidfd);
unlink(pidfile);
}
}
void
-handle_exit_timeout(_unused struct interface *iface)
+handle_exit_timeout(_unused void *arg)
{
logger(LOG_ERR, "timed out");
exit(EXIT_FAILURE);
@@ -186,7 +192,7 @@ close_sockets(struct interface *iface)
static void
send_message(struct interface *iface, int type,
- void (*function)(struct interface *))
+ void (*callback)(void *))
{
struct if_state *state = iface->state;
struct dhcp_message *dhcp;
@@ -196,7 +202,7 @@ send_message(struct interface *iface, int type,
in_addr_t a = 0;
struct timeval tv;
- if (!function)
+ if (!callback)
logger(LOG_DEBUG, "%s: sending %s with xid 0x%x",
iface->name, get_dhcp_op(type), state->xid);
else {
@@ -243,31 +249,33 @@ send_message(struct interface *iface, int type,
iface->name, strerror(errno));
}
free(dhcp);
- if (function)
- add_timeout_tv(&tv, function, iface);
+ if (callback)
+ add_timeout_tv(&tv, callback, iface);
}
static void
-send_discover(struct interface *iface)
+send_discover(void *arg)
{
- send_message(iface, DHCP_DISCOVER, send_discover);
+ send_message((struct interface *)arg, DHCP_DISCOVER, send_discover);
}
void
-send_request(struct interface *iface)
+send_request(void *arg)
{
- send_message(iface, DHCP_REQUEST, send_request);
+ send_message((struct interface *)arg, DHCP_REQUEST, send_request);
}
static void
-send_renew(struct interface *iface)
+send_renew(void *arg)
{
- send_message(iface, DHCP_REQUEST, send_renew);
+ send_message((struct interface *)arg, DHCP_REQUEST, send_renew);
}
void
-start_renew(struct interface *iface)
+start_renew(void *arg)
{
+ struct interface *iface = arg;
+
logger(LOG_INFO, "%s: renewing lease of %s",
iface->name, inet_ntoa(iface->state->lease.addr));
iface->state->state = DHS_RENEWING;
@@ -276,14 +284,16 @@ start_renew(struct interface *iface)
}
static void
-send_rebind(struct interface *iface)
+send_rebind(void *arg)
{
- send_message(iface, DHCP_REQUEST, send_rebind);
+ send_message((struct interface *)arg, DHCP_REQUEST, send_rebind);
}
void
-start_rebind(struct interface *iface)
+start_rebind(void *arg)
{
+ struct interface *iface = arg;
+
logger(LOG_ERR, "%s: failed to renew, attmepting to rebind",
iface->name);
iface->state->state = DHS_REBINDING;
@@ -293,8 +303,9 @@ start_rebind(struct interface *iface)
}
void
-start_expire(struct interface *iface)
+start_expire(void *arg)
{
+ struct interface *iface = arg;
int ll = IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr));
logger(LOG_ERR, "%s: lease expired", iface->name);
@@ -468,8 +479,9 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
}
static void
-handle_dhcp_packet(struct interface *iface)
+handle_dhcp_packet(void *arg)
{
+ struct interface *iface = arg;
uint8_t *packet;
struct dhcp_message *dhcp = NULL;
const uint8_t *pp;
@@ -552,8 +564,9 @@ open_sockets(struct interface *iface)
}
static void
-handle_link(struct interface *iface)
+handle_link(_unused void *arg)
{
+ struct interface *iface;
int retval;
retval = link_changed(linkfd, ifaces);
@@ -593,8 +606,9 @@ handle_link(struct interface *iface)
}
void
-start_discover(struct interface *iface)
+start_discover(void *arg)
{
+ struct interface *iface = arg;
struct if_options *ifo = iface->state->options;
iface->state->state = DHS_DISCOVERING;
@@ -630,9 +644,24 @@ start_reboot(struct interface *iface)
send_rebind(iface);
}
+static void
+send_release(struct interface *iface)
+{
+ if (iface->state->lease.addr.s_addr &&
+ !IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)))
+ {
+ logger(LOG_INFO, "%s: releasing lease of %s",
+ iface->name, inet_ntoa(iface->state->lease.addr));
+ open_sockets(iface);
+ send_message(iface, DHCP_RELEASE, NULL);
+ }
+}
+
void
-start_interface(struct interface *iface)
+start_interface(void *arg)
{
+ struct interface *iface = arg;
+
iface->start_uptime = uptime();
if (!iface->state->lease.addr.s_addr)
start_discover(iface);
@@ -643,25 +672,18 @@ start_interface(struct interface *iface)
}
static void
-init_state(struct interface *iface, int argc, char **argv)
+configure_interface(struct interface *iface, int argc, char **argv)
{
- struct if_state *ifs;
+ struct if_state *ifs = iface->state;
struct if_options *ifo;
uint8_t *duid;
size_t len = 0, ifl;
- if (iface->state) {
- ifs = iface->state;
- free_options(ifs->options);
- } else
- ifs = iface->state = xzalloc(sizeof(*ifs));
-
- ifs->state = DHS_INIT;
- ifs->nakoff = 1;
+ free_options(ifs->options);
ifo = ifs->options = read_config(cffile, iface->name);
add_options(ifo, argc, argv);
- if (ifo->metric)
+ if (ifo->metric != -1)
iface->metric = ifo->metric;
if (*ifo->clientid) {
@@ -696,10 +718,26 @@ init_state(struct interface *iface, int argc, char **argv)
}
}
- if (!(ifo->options & DHCPCD_TEST))
+}
+
+static void
+init_state(struct interface *iface, int argc, char **argv)
+{
+ struct if_state *ifs;
+
+ if (iface->state) {
+ ifs = iface->state;
+ } else
+ ifs = iface->state = xzalloc(sizeof(*ifs));
+
+ ifs->state = DHS_INIT;
+ ifs->nakoff = 1;
+ configure_interface(iface, argc, argv);
+
+ if (!(ifs->options->options & DHCPCD_TEST))
run_script(iface, "PREINIT");
- if (ifo->options & DHCPCD_LINK) {
+ if (ifs->options->options & DHCPCD_LINK) {
switch (carrier_status(iface->name)) {
case 0:
ifs->carrier = LINK_DOWN;
@@ -719,9 +757,11 @@ init_state(struct interface *iface, int argc, char **argv)
}
static void
-handle_signal(struct interface *iface)
+handle_signal(_unused void *arg)
{
+ struct interface *iface;
int sig = signal_read();
+ int do_reboot = 0, do_release = 0;
switch (sig) {
case SIGINT:
@@ -730,6 +770,14 @@ handle_signal(struct interface *iface)
case SIGTERM:
logger(LOG_INFO, "received SIGTERM, stopping");
break;
+ case SIGALRM:
+ logger(LOG_INFO, "received SIGALRM, rebinding lease");
+ do_reboot = 1;
+ break;
+ case SIGHUP:
+ logger(LOG_INFO, "received SIGHUP, releasing lease");
+ do_release = 1;
+ break;
default:
logger (LOG_ERR,
"received signal %d, but don't know what to do with it",
@@ -740,18 +788,97 @@ handle_signal(struct interface *iface)
for (iface = ifaces; iface; iface = iface->next) {
if (!iface->state)
continue;
- if (!(iface->state->options->options & DHCPCD_PERSISTENT))
- drop_config(iface, "STOP");
+ if (do_reboot)
+ start_reboot(iface);
+ else {
+ if (do_release)
+ send_release(iface);
+ if (!(iface->state->options->options & DHCPCD_PERSISTENT))
+ drop_config(iface, do_release ? "RELEASE" : "STOP");
+ }
}
exit(EXIT_FAILURE);
}
int
+handle_args(int argc, char **argv)
+{
+ struct interface *ifs, *ifp, *ifl = NULL, *ifn;
+ int do_exit = 0, do_release = 0, do_reboot = 0, opt, oi = 0;
+
+ optind = 0;
+ while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+ {
+ switch (opt) {
+ case 'k':
+ do_release = 1;
+ break;
+ case 'n':
+ do_reboot = 1;
+ break;
+ case 'x':
+ do_exit = 1;
+ break;
+ }
+ }
+
+ /* We only deal with one interface here */
+ if (optind == argc) {
+ logger(LOG_ERR, "handle_args: no interface");
+ return -1;
+ }
+
+ if (do_release || do_reboot || do_exit) {
+ oi = optind;
+ while (oi < argc) {
+ for (ifp = ifaces; ifp && (ifn = ifp->next, 1); ifp = ifn) {
+ if (strcmp(ifp->name, argv[oi]) == 0) {
+ if (do_release)
+ send_release(ifp);
+ if (do_exit || do_release) {
+ drop_config(ifp, do_release ? "RELEASE" : "STOP");
+ close_sockets(ifp);
+ delete_timeout(NULL, ifp);
+ if (ifl)
+ ifl->next = ifp->next;
+ else
+ ifaces = ifp->next;
+ free_interface(ifp);
+ continue;
+ } else if (do_reboot) {
+ configure_interface(ifp, argc, argv);
+ start_reboot(ifp);
+ }
+ }
+ ifl = ifp;
+ }
+ oi++;
+ }
+ return 0;
+ }
+
+ if ((ifs = discover_interfaces(argc, argv))) {
+ argc += optind;
+ argv -= optind;
+ for (ifp = ifs; ifp; ifp = ifp->next)
+ init_state(ifp, argc, argv);
+ if (ifaces) {
+ ifp = ifaces;
+ while (ifp->next)
+ ifp = ifp->next;
+ ifp->next = ifs;
+ } else
+ ifaces = ifs;
+ }
+ return 0;
+}
+
+int
main(int argc, char **argv)
{
struct if_options *ifo;
struct interface *iface;
- int opt, oi = 0, test = 0, signal_fd, sig = 0, i;
+ int opt, oi = 0, test = 0, signal_fd, sig = 0, i, control_fd;
pid_t pid;
struct timespec ts;
@@ -781,6 +908,12 @@ main(int argc, char **argv)
case 'f':
strlcpy(cffile, optarg, sizeof(cffile));
break;
+ case 'k':
+ sig = SIGHUP;
+ break;
+ case 'n':
+ sig = SIGALRM;
+ break;
case 'x':
sig = SIGTERM;
break;
@@ -803,27 +936,45 @@ main(int argc, char **argv)
usage();
exit(EXIT_FAILURE);
}
- if (test)
- ifo->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
-#ifdef THERE_IS_NO_FORK
- ifo->options &= ~DHCPCD_DAEMONISE;
-#endif
/* If we have any other args, we should run as a single dhcpcd instance
* for that interface. */
if (optind == argc - 1)
snprintf(pidfile, sizeof(pidfile), PIDFILE, "-", argv[optind]);
- else
+ else {
snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "");
-
- if (geteuid())
- logger(LOG_WARNING, PACKAGE " will not work correctly unless"
- " run as root");
+ master = 1;
+ }
+
+ if (test)
+ ifo->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
+#ifdef THERE_IS_NO_FORK
+ ifo->options &= ~DHCPCD_DAEMONISE;
+#endif
chdir("/");
umask(022);
atexit(cleanup);
+ if (!master) {
+ control_fd = open_control();
+ if (control_fd != -1) {
+ logger(LOG_INFO, "sending commands to master dhcpcd process");
+ i = send_control(argc, argv);
+ if (i > 0) {
+ logger(LOG_DEBUG, "send OK");
+ exit(EXIT_SUCCESS);
+ } else {
+ logger(LOG_ERR, "failed to send commands");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ if (geteuid())
+ logger(LOG_WARNING, PACKAGE " will not work correctly unless"
+ " run as root");
+
if (sig != 0) {
i = -1;
pid = read_pid();
@@ -886,6 +1037,13 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
add_event(signal_fd, handle_signal, NULL);
+ if (master) {
+ if (start_control() == -1) {
+ logger(LOG_ERR, "start_control: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
if (ifo->options & DHCPCD_LINK) {
linkfd = open_link_socket();
if (linkfd == -1)