aboutsummaryrefslogtreecommitdiffstats
path: root/bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'bind.c')
-rw-r--r--bind.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/bind.c b/bind.c
new file mode 100644
index 0000000..eed64a6
--- /dev/null
+++ b/bind.c
@@ -0,0 +1,234 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+#ifdef BSD
+# include <paths.h>
+#endif
+#include <signal.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "arp.h"
+#include "bind.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcpcd.h"
+#include "eloop.h"
+#include "if-options.h"
+#include "net.h"
+#include "signals.h"
+
+#ifndef _PATH_DEVNULL
+# define _PATH_DEVNULL "/dev/null"
+#endif
+
+/* We do things after aquiring the lease, so ensure we have enough time for them */
+#define DHCP_MIN_LEASE 20
+
+#ifndef THERE_IS_NO_FORK
+pid_t
+daemonise(void)
+{
+ pid_t pid;
+ sigset_t full;
+ sigset_t old;
+ char buf = '\0';
+ int sidpipe[2], fd;
+
+ if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
+ return 0;
+ sigfillset(&full);
+ sigprocmask(SIG_SETMASK, &full, &old);
+ /* Setup a signal pipe so parent knows when to exit. */
+ if (pipe(sidpipe) == -1) {
+ syslog(LOG_ERR, "pipe: %m");
+ return -1;
+ }
+ syslog(LOG_DEBUG, "forking to background");
+ switch (pid = fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ exit(EXIT_FAILURE);
+ /* NOTREACHED */
+ case 0:
+ setsid();
+ /* Notify parent it's safe to exit as we've detached. */
+ close(sidpipe[0]);
+ if (write(sidpipe[1], &buf, 1) == -1)
+ syslog(LOG_ERR, "failed to notify parent: %m");
+ close(sidpipe[1]);
+ if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > STDERR_FILENO)
+ close(fd);
+ }
+ break;
+ default:
+ signal_reset();
+ /* Wait for child to detach */
+ close(sidpipe[1]);
+ if (read(sidpipe[0], &buf, 1) == -1)
+ syslog(LOG_ERR, "failed to read child: %m");
+ close(sidpipe[0]);
+ break;
+ }
+ /* Done with the fd now */
+ if (pid != 0) {
+ syslog(LOG_INFO, "forked to background, child pid %d",pid);
+ writepid(pidfd, pid);
+ close(pidfd);
+ pidfd = -1;
+ exit(EXIT_SUCCESS);
+ }
+ options |= DHCPCD_DAEMONISED;
+ sigprocmask(SIG_SETMASK, &old, NULL);
+ return pid;
+}
+#endif
+
+void
+bind_interface(void *arg)
+{
+ struct interface *iface = arg;
+ struct if_state *state = iface->state;
+ struct if_options *ifo = state->options;
+ struct dhcp_lease *lease = &state->lease;
+ struct timeval tv;
+
+ /* We're binding an address now - ensure that sockets are closed */
+ close_sockets(iface);
+ state->reason = NULL;
+ delete_timeout(handle_exit_timeout, NULL);
+ if (clock_monotonic)
+ get_monotonic(&lease->boundtime);
+ state->xid = 0;
+ free(state->old);
+ state->old = state->new;
+ state->new = state->offer;
+ state->offer = NULL;
+ get_lease(lease, state->new);
+ if (ifo->options & DHCPCD_STATIC) {
+ syslog(LOG_INFO, "%s: using static address %s",
+ iface->name, inet_ntoa(lease->addr));
+ lease->leasetime = ~0U;
+ lease->net.s_addr = ifo->req_mask.s_addr;
+ state->reason = "STATIC";
+ } else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
+ syslog(LOG_INFO, "%s: using IPv4LL address %s",
+ iface->name, inet_ntoa(lease->addr));
+ lease->leasetime = ~0U;
+ state->reason = "IPV4LL";
+ } else if (ifo->options & DHCPCD_INFORM) {
+ if (ifo->req_addr.s_addr != 0)
+ lease->addr.s_addr = ifo->req_addr.s_addr;
+ else
+ lease->addr.s_addr = iface->addr.s_addr;
+ syslog(LOG_INFO, "%s: received approval for %s", iface->name,
+ inet_ntoa(lease->addr));
+ lease->leasetime = ~0U;
+ state->reason = "INFORM";
+ } else {
+ if (gettimeofday(&tv, NULL) == 0)
+ lease->leasedfrom = tv.tv_sec;
+ else if (lease->frominfo)
+ state->reason = "TIMEOUT";
+ if (lease->leasetime == ~0U) {
+ lease->renewaltime =
+ lease->rebindtime =
+ lease->leasetime;
+ syslog(LOG_INFO, "%s: leased %s for infinity",
+ iface->name, inet_ntoa(lease->addr));
+ } else {
+ if (lease->leasetime < DHCP_MIN_LEASE) {
+ syslog(LOG_WARNING,
+ "%s: minimum lease is %d seconds",
+ iface->name, DHCP_MIN_LEASE);
+ lease->leasetime = DHCP_MIN_LEASE;
+ }
+ if (lease->rebindtime == 0)
+ lease->rebindtime = lease->leasetime * T2;
+ else if (lease->rebindtime >= lease->leasetime) {
+ lease->rebindtime = lease->leasetime * T2;
+ syslog(LOG_ERR,
+ "%s: rebind time greater than lease "
+ "time, forcing to %u seconds",
+ iface->name, lease->rebindtime);
+ }
+ if (lease->renewaltime == 0)
+ lease->renewaltime = lease->leasetime * T1;
+ else if (lease->renewaltime > lease->rebindtime) {
+ lease->renewaltime = lease->leasetime * T1;
+ syslog(LOG_ERR,
+ "%s: renewal time greater than rebind "
+ "time, forcing to %u seconds",
+ iface->name, lease->renewaltime);
+ }
+ syslog(LOG_INFO,
+ "%s: leased %s for %u seconds", iface->name,
+ inet_ntoa(lease->addr), lease->leasetime);
+ }
+ }
+ if (options & DHCPCD_TEST) {
+ state->reason = "TEST";
+ run_script(iface);
+ exit(EXIT_SUCCESS);
+ }
+ if (state->reason == NULL) {
+ if (state->old) {
+ if (state->old->yiaddr == state->new->yiaddr &&
+ lease->server.s_addr)
+ state->reason = "RENEW";
+ else
+ state->reason = "REBIND";
+ } else if (state->state == DHS_REBOOT)
+ state->reason = "REBOOT";
+ else
+ state->reason = "BOUND";
+ }
+ if (lease->leasetime == ~0U)
+ lease->renewaltime = lease->rebindtime = lease->leasetime;
+ else {
+ add_timeout_sec(lease->renewaltime, start_renew, iface);
+ add_timeout_sec(lease->rebindtime, start_rebind, iface);
+ add_timeout_sec(lease->leasetime, start_expire, iface);
+ }
+ ifo->options &= ~ DHCPCD_CSR_WARNED;
+ configure(iface);
+ daemonise();
+ state->state = DHS_BOUND;
+ if (ifo->options & DHCPCD_ARP) {
+ state->claims = 0;
+ send_arp_announce(iface);
+ }
+}