2007-11-15 19:35:53 +08:00
|
|
|
/*
|
2007-11-08 00:26:41 +08:00
|
|
|
* dhcpcd - DHCP client daemon
|
2013-02-02 22:05:55 +08:00
|
|
|
* Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
|
2007-11-15 19:35:53 +08:00
|
|
|
* 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.
|
2006-11-28 04:23:22 +08:00
|
|
|
*/
|
|
|
|
|
2013-02-02 22:05:55 +08:00
|
|
|
const char copyright[] = "Copyright (c) 2006-2013 Roy Marples";
|
2007-11-08 18:38:54 +08:00
|
|
|
|
2007-05-13 20:28:54 +08:00
|
|
|
#include <sys/file.h>
|
2009-04-17 21:42:44 +08:00
|
|
|
#include <sys/socket.h>
|
2008-08-13 23:09:13 +08:00
|
|
|
#include <sys/stat.h>
|
2009-07-14 21:59:30 +08:00
|
|
|
#include <sys/time.h>
|
2006-12-15 19:23:32 +08:00
|
|
|
#include <sys/types.h>
|
2009-01-26 23:15:28 +08:00
|
|
|
#include <sys/uio.h>
|
2012-10-09 21:20:50 +08:00
|
|
|
#include <sys/utsname.h>
|
2008-03-21 00:47:51 +08:00
|
|
|
|
2013-02-04 22:12:48 +08:00
|
|
|
#include <net/route.h> /* For RTM_CHGADDR */
|
|
|
|
|
2008-07-03 01:05:41 +08:00
|
|
|
#include <ctype.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <getopt.h>
|
2008-09-02 21:28:11 +08:00
|
|
|
#include <limits.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
#include <paths.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2008-09-06 02:24:34 +08:00
|
|
|
#include <syslog.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
#include <unistd.h>
|
2008-08-12 20:20:25 +08:00
|
|
|
#include <time.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
#include "arp.h"
|
2007-05-11 00:08:49 +08:00
|
|
|
#include "config.h"
|
2008-09-02 21:28:11 +08:00
|
|
|
#include "common.h"
|
2008-09-04 00:49:28 +08:00
|
|
|
#include "control.h"
|
2006-11-28 04:23:22 +08:00
|
|
|
#include "dhcpcd.h"
|
2012-10-12 18:31:51 +08:00
|
|
|
#include "dhcp6.h"
|
2008-09-02 21:28:11 +08:00
|
|
|
#include "eloop.h"
|
|
|
|
#include "if-options.h"
|
2008-09-10 01:07:48 +08:00
|
|
|
#include "if-pref.h"
|
2013-02-02 22:05:55 +08:00
|
|
|
#include "ipv4.h"
|
2012-07-06 00:37:41 +08:00
|
|
|
#include "ipv6.h"
|
|
|
|
#include "ipv6ns.h"
|
2011-12-15 10:35:47 +08:00
|
|
|
#include "ipv6rs.h"
|
2008-09-02 21:28:11 +08:00
|
|
|
#include "net.h"
|
2012-02-04 23:15:25 +08:00
|
|
|
#include "platform.h"
|
2013-02-02 22:05:55 +08:00
|
|
|
#include "script.h"
|
2008-09-02 21:28:11 +08:00
|
|
|
#include "signals.h"
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2009-12-03 21:30:09 +08:00
|
|
|
/* Wait N nanoseconds between sending a RELEASE and dropping the address.
|
|
|
|
* This gives the kernel enough time to actually send it. */
|
|
|
|
#define RELEASE_DELAY_S 0
|
|
|
|
#define RELEASE_DELAY_NS 10000000
|
|
|
|
|
2012-10-09 21:20:50 +08:00
|
|
|
char vendor[VENDORCLASSID_MAX_LEN];
|
2008-09-02 21:28:11 +08:00
|
|
|
int pidfd = -1;
|
2008-09-10 01:07:48 +08:00
|
|
|
struct interface *ifaces = NULL;
|
2013-02-04 06:55:45 +08:00
|
|
|
struct if_options *if_options = NULL;
|
2008-09-11 17:38:02 +08:00
|
|
|
int ifac = 0;
|
|
|
|
char **ifav = NULL;
|
|
|
|
int ifdc = 0;
|
|
|
|
char **ifdv = NULL;
|
2008-09-10 01:07:48 +08:00
|
|
|
|
2012-11-11 00:38:52 +08:00
|
|
|
sigset_t dhcpcd_sigset;
|
|
|
|
|
2008-10-06 20:45:32 +08:00
|
|
|
static char *cffile;
|
2008-09-05 22:16:53 +08:00
|
|
|
static char *pidfile;
|
2013-02-04 21:30:35 +08:00
|
|
|
static int linkfd = -1;
|
2012-11-11 00:38:52 +08:00
|
|
|
static char **ifv;
|
|
|
|
static int ifc;
|
|
|
|
static char **margv;
|
|
|
|
static int margc;
|
2008-04-19 07:12:44 +08:00
|
|
|
|
2008-03-21 00:47:51 +08:00
|
|
|
static pid_t
|
2008-09-02 21:28:11 +08:00
|
|
|
read_pid(void)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
FILE *fp;
|
2009-01-29 21:01:29 +08:00
|
|
|
pid_t pid;
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2008-03-21 00:47:51 +08:00
|
|
|
if ((fp = fopen(pidfile, "r")) == NULL) {
|
2007-04-11 21:18:33 +08:00
|
|
|
errno = ENOENT;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-01-29 21:01:29 +08:00
|
|
|
if (fscanf(fp, "%d", &pid) != 1)
|
|
|
|
pid = 0;
|
2008-03-21 00:47:51 +08:00
|
|
|
fclose(fp);
|
|
|
|
return pid;
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
|
|
|
|
2008-03-21 00:47:51 +08:00
|
|
|
static void
|
|
|
|
usage(void)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2012-03-24 18:41:40 +08:00
|
|
|
|
2012-10-12 18:31:51 +08:00
|
|
|
printf("usage: "PACKAGE"\t[-46ABbDdEGgHJKkLnpqTVw]\n"
|
2012-03-24 18:41:40 +08:00
|
|
|
"\t\t[-C, --nohook hook] [-c, --script script]\n"
|
|
|
|
"\t\t[-e, --env value] [-F, --fqdn FQDN] [-f, --config file]\n"
|
|
|
|
"\t\t[-h, --hostname hostname] [-I, --clientid clientid]\n"
|
|
|
|
"\t\t[-i, --vendorclassid vendorclassid] [-l, --leasetime seconds]\n"
|
|
|
|
"\t\t[-m, --metric metric] [-O, --nooption option]\n"
|
|
|
|
"\t\t[-o, --option option] [-Q, --require option]\n"
|
|
|
|
"\t\t[-r, --request address] [-S, --static value]\n"
|
|
|
|
"\t\t[-s, --inform address[/cidr]] [-t, --timeout seconds]\n"
|
|
|
|
"\t\t[-u, --userclass class] [-v, --vendor code, value]\n"
|
|
|
|
"\t\t[-W, --whitelist address[/cidr]] [-y, --reboot seconds]\n"
|
|
|
|
"\t\t[-X, --blacklist address[/cidr]] [-Z, --denyinterfaces pattern]\n"
|
|
|
|
"\t\t[-z, --allowinterfaces pattern] [interface] [...]\n"
|
|
|
|
" "PACKAGE"\t-k, --release [interface]\n"
|
|
|
|
" "PACKAGE"\t-U, --dumplease interface\n"
|
2012-08-18 21:58:53 +08:00
|
|
|
" "PACKAGE"\t--version\n"
|
2012-03-24 18:41:40 +08:00
|
|
|
" "PACKAGE"\t-x, --exit [interface]\n");
|
2008-05-21 00:05:15 +08:00
|
|
|
}
|
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
static void
|
|
|
|
cleanup(void)
|
2008-05-21 00:05:15 +08:00
|
|
|
{
|
2008-09-02 21:28:11 +08:00
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
struct interface *iface;
|
2008-09-11 17:38:02 +08:00
|
|
|
int i;
|
2008-09-02 21:28:11 +08:00
|
|
|
|
2010-08-24 17:34:21 +08:00
|
|
|
free_options(if_options);
|
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
while (ifaces) {
|
|
|
|
iface = ifaces;
|
|
|
|
ifaces = iface->next;
|
|
|
|
free_interface(iface);
|
2008-05-21 00:05:15 +08:00
|
|
|
}
|
2008-09-11 17:38:02 +08:00
|
|
|
|
|
|
|
for (i = 0; i < ifac; i++)
|
|
|
|
free(ifav[i]);
|
|
|
|
free(ifav);
|
|
|
|
for (i = 0; i < ifdc; i++)
|
|
|
|
free(ifdv[i]);
|
|
|
|
free(ifdv);
|
2008-09-02 21:28:11 +08:00
|
|
|
#endif
|
2008-05-21 00:05:15 +08:00
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
if (linkfd != -1)
|
|
|
|
close(linkfd);
|
|
|
|
if (pidfd > -1) {
|
2008-09-05 15:22:03 +08:00
|
|
|
if (options & DHCPCD_MASTER) {
|
2012-11-13 18:17:19 +08:00
|
|
|
if (control_stop() == -1)
|
|
|
|
syslog(LOG_ERR, "control_stop: %m");
|
2008-09-04 00:49:28 +08:00
|
|
|
}
|
2008-09-02 21:28:11 +08:00
|
|
|
close(pidfd);
|
|
|
|
unlink(pidfile);
|
|
|
|
}
|
2008-09-05 22:16:53 +08:00
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
free(pidfile);
|
|
|
|
#endif
|
2012-11-10 16:44:48 +08:00
|
|
|
|
|
|
|
if (options & DHCPCD_STARTED && !(options & DHCPCD_FORKED))
|
|
|
|
syslog(LOG_INFO, "exited");
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
|
|
|
|
2008-11-10 19:15:27 +08:00
|
|
|
/* ARGSUSED */
|
2013-02-02 22:05:55 +08:00
|
|
|
static void
|
2008-09-04 00:49:28 +08:00
|
|
|
handle_exit_timeout(_unused void *arg)
|
2008-09-02 21:28:11 +08:00
|
|
|
{
|
2009-10-09 03:56:52 +08:00
|
|
|
int timeout;
|
|
|
|
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, "timed out");
|
2012-11-07 07:40:15 +08:00
|
|
|
if (!(options & DHCPCD_IPV4) || !(options & DHCPCD_TIMEOUT_IPV4LL)) {
|
2010-06-26 17:17:54 +08:00
|
|
|
if (options & DHCPCD_MASTER) {
|
|
|
|
daemonise();
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2009-10-09 03:56:52 +08:00
|
|
|
options &= ~DHCPCD_TIMEOUT_IPV4LL;
|
2011-11-23 07:44:32 +08:00
|
|
|
timeout = (PROBE_NUM * PROBE_MAX) + (PROBE_WAIT * 2);
|
2009-10-09 03:56:52 +08:00
|
|
|
syslog(LOG_WARNING, "allowing %d seconds for IPv4LL timeout", timeout);
|
2012-11-13 19:25:51 +08:00
|
|
|
eloop_timeout_add_sec(timeout, handle_exit_timeout, NULL);
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
|
|
|
|
2013-02-02 22:05:55 +08:00
|
|
|
pid_t
|
|
|
|
daemonise(void)
|
2008-09-02 21:28:11 +08:00
|
|
|
{
|
2013-02-02 22:05:55 +08:00
|
|
|
#ifdef THERE_IS_NO_FORK
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
pid_t pid;
|
|
|
|
char buf = '\0';
|
|
|
|
int sidpipe[2], fd;
|
|
|
|
|
|
|
|
eloop_timeout_delete(handle_exit_timeout, NULL);
|
|
|
|
if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
|
|
|
|
return 0;
|
|
|
|
/* 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);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* 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;
|
|
|
|
options |= DHCPCD_FORKED;
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
options |= DHCPCD_DAEMONISED;
|
|
|
|
return pid;
|
|
|
|
#endif
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
|
|
|
|
2009-01-28 02:09:02 +08:00
|
|
|
struct interface *
|
|
|
|
find_interface(const char *ifname)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
|
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
|
|
|
if (strcmp(ifp->name, ifname) == 0)
|
|
|
|
return ifp;
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-09-16 21:17:23 +08:00
|
|
|
|
2008-09-04 17:43:52 +08:00
|
|
|
static void
|
2009-01-21 00:33:11 +08:00
|
|
|
stop_interface(struct interface *iface)
|
2008-09-04 17:43:52 +08:00
|
|
|
{
|
|
|
|
struct interface *ifp, *ifl = NULL;
|
|
|
|
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_INFO, "%s: removing interface", iface->name);
|
2012-07-06 00:37:41 +08:00
|
|
|
|
|
|
|
// Remove the interface from our list
|
2008-09-04 17:43:52 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next) {
|
|
|
|
if (ifp == iface)
|
|
|
|
break;
|
|
|
|
ifl = ifp;
|
|
|
|
}
|
|
|
|
if (ifl)
|
2008-09-12 06:55:27 +08:00
|
|
|
ifl->next = ifp->next;
|
2008-09-04 17:43:52 +08:00
|
|
|
else
|
2008-09-12 06:55:27 +08:00
|
|
|
ifaces = ifp->next;
|
2012-07-06 00:37:41 +08:00
|
|
|
|
2012-11-12 03:56:01 +08:00
|
|
|
dhcp6_drop(iface, NULL);
|
2012-07-06 00:37:41 +08:00
|
|
|
ipv6rs_drop(iface);
|
2013-02-02 22:05:55 +08:00
|
|
|
// if (strcmp(iface->state->reason, "RELEASE") != 0)
|
|
|
|
dhcp_drop(iface, "STOP");
|
|
|
|
dhcp_close(iface);
|
2012-11-13 19:25:51 +08:00
|
|
|
eloop_timeout_delete(NULL, iface);
|
2008-09-04 17:43:52 +08:00
|
|
|
free_interface(ifp);
|
2009-07-12 02:54:43 +08:00
|
|
|
if (!(options & (DHCPCD_MASTER | DHCPCD_TEST)))
|
2008-09-04 17:43:52 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2009-01-02 04:51:04 +08:00
|
|
|
static void
|
2013-02-03 18:35:59 +08:00
|
|
|
configure_interface1(struct interface *ifp)
|
2009-01-02 04:51:04 +08:00
|
|
|
{
|
2013-02-03 18:35:59 +08:00
|
|
|
struct if_options *ifo = ifp->options;
|
2009-01-02 04:51:04 +08:00
|
|
|
|
2010-03-05 23:47:46 +08:00
|
|
|
/* Do any platform specific configuration */
|
2013-02-03 18:35:59 +08:00
|
|
|
if_conf(ifp);
|
2010-03-05 23:47:46 +08:00
|
|
|
|
2013-02-03 18:35:59 +08:00
|
|
|
if (ifp->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM))
|
2009-03-24 04:10:02 +08:00
|
|
|
ifo->options |= DHCPCD_STATIC;
|
2013-02-03 18:35:59 +08:00
|
|
|
if (ifp->flags & IFF_NOARP ||
|
2009-03-24 06:02:37 +08:00
|
|
|
ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
|
|
|
|
ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
|
2013-02-03 18:35:59 +08:00
|
|
|
if (!(ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK | IFF_MULTICAST)))
|
2011-12-15 11:37:27 +08:00
|
|
|
ifo->options &= ~DHCPCD_IPV6RS;
|
2013-02-03 18:35:59 +08:00
|
|
|
if (ifo->options & DHCPCD_LINK && carrier_status(ifp) == -1)
|
2009-03-20 01:52:12 +08:00
|
|
|
ifo->options &= ~DHCPCD_LINK;
|
|
|
|
|
2009-01-02 04:51:04 +08:00
|
|
|
if (ifo->metric != -1)
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->metric = ifo->metric;
|
2009-01-02 04:51:04 +08:00
|
|
|
|
2012-07-13 16:22:04 +08:00
|
|
|
/* We want to disable kernel interface RA as early as possible. */
|
|
|
|
if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS) {
|
2013-02-03 18:35:59 +08:00
|
|
|
if (check_ipv6(ifp->name) != 1)
|
2012-07-13 16:22:04 +08:00
|
|
|
ifo->options &= ~DHCPCD_IPV6RS;
|
|
|
|
}
|
|
|
|
|
2009-01-02 04:51:04 +08:00
|
|
|
/* If we haven't specified a ClientID and our hardware address
|
|
|
|
* length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
|
|
|
|
* of the hardware address family and the hardware address. */
|
2013-02-03 18:35:59 +08:00
|
|
|
if (ifp->hwlen > DHCP_CHADDR_LEN)
|
2009-01-02 04:51:04 +08:00
|
|
|
ifo->options |= DHCPCD_CLIENTID;
|
|
|
|
|
2010-01-29 04:12:54 +08:00
|
|
|
/* Firewire and InfiniBand interfaces require ClientID and
|
|
|
|
* the broadcast option being set. */
|
2013-02-03 18:35:59 +08:00
|
|
|
switch (ifp->family) {
|
2010-01-29 04:12:54 +08:00
|
|
|
case ARPHRD_IEEE1394: /* FALLTHROUGH */
|
|
|
|
case ARPHRD_INFINIBAND:
|
|
|
|
ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
|
|
|
|
break;
|
|
|
|
}
|
2009-01-02 04:51:04 +08:00
|
|
|
}
|
|
|
|
|
2009-03-31 16:35:38 +08:00
|
|
|
int
|
2013-02-03 18:35:59 +08:00
|
|
|
select_profile(struct interface *ifp, const char *profile)
|
2009-03-31 16:35:38 +08:00
|
|
|
{
|
|
|
|
struct if_options *ifo;
|
2010-11-09 08:34:38 +08:00
|
|
|
int ret;
|
2009-03-31 16:35:38 +08:00
|
|
|
|
2010-11-09 08:34:38 +08:00
|
|
|
ret = 0;
|
2013-02-03 18:35:59 +08:00
|
|
|
ifo = read_config(cffile, ifp->name, ifp->ssid, profile);
|
2009-03-31 16:35:38 +08:00
|
|
|
if (ifo == NULL) {
|
2013-02-03 18:35:59 +08:00
|
|
|
syslog(LOG_DEBUG, "%s: no profile %s", ifp->name, profile);
|
2010-11-09 08:34:38 +08:00
|
|
|
ret = -1;
|
|
|
|
goto exit;
|
2009-03-31 16:35:38 +08:00
|
|
|
}
|
|
|
|
if (profile != NULL) {
|
2013-02-04 06:55:45 +08:00
|
|
|
strlcpy(ifp->profile, profile, sizeof(ifp->profile));
|
2009-03-31 16:35:38 +08:00
|
|
|
syslog(LOG_INFO, "%s: selected profile %s",
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->name, profile);
|
2009-03-31 16:35:38 +08:00
|
|
|
} else
|
2013-02-04 06:55:45 +08:00
|
|
|
*ifp->profile = '\0';
|
2013-02-03 18:35:59 +08:00
|
|
|
free_options(ifp->options);
|
|
|
|
ifp->options = ifo;
|
2010-11-09 08:34:38 +08:00
|
|
|
|
|
|
|
exit:
|
|
|
|
if (profile)
|
2013-02-03 18:35:59 +08:00
|
|
|
configure_interface1(ifp);
|
2010-11-09 08:34:38 +08:00
|
|
|
return ret;
|
2009-03-31 16:35:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-02-03 18:35:59 +08:00
|
|
|
configure_interface(struct interface *ifp, int argc, char **argv)
|
2009-03-31 16:35:38 +08:00
|
|
|
{
|
2013-02-03 18:35:59 +08:00
|
|
|
|
|
|
|
select_profile(ifp, NULL);
|
|
|
|
add_options(ifp->options, argc, argv);
|
|
|
|
configure_interface1(ifp);
|
2009-03-31 16:35:38 +08:00
|
|
|
}
|
|
|
|
|
2011-11-23 17:03:24 +08:00
|
|
|
void
|
|
|
|
handle_carrier(int action, int flags, const char *ifname)
|
2008-09-02 21:28:11 +08:00
|
|
|
{
|
2013-02-03 18:35:59 +08:00
|
|
|
struct interface *ifp;
|
2009-10-14 23:16:07 +08:00
|
|
|
int carrier;
|
2008-09-04 22:08:14 +08:00
|
|
|
|
2009-04-19 05:43:23 +08:00
|
|
|
if (!(options & DHCPCD_LINK))
|
|
|
|
return;
|
2013-02-03 18:35:59 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
|
|
|
if (strcmp(ifp->name, ifname) == 0)
|
2008-09-04 22:08:14 +08:00
|
|
|
break;
|
2013-02-03 18:35:59 +08:00
|
|
|
if (!ifp) {
|
2011-11-23 17:03:24 +08:00
|
|
|
if (options & DHCPCD_LINK)
|
|
|
|
handle_interface(1, ifname);
|
|
|
|
return;
|
|
|
|
}
|
2013-02-03 18:35:59 +08:00
|
|
|
if (!(ifp->options->options & DHCPCD_LINK))
|
2008-09-02 21:28:11 +08:00
|
|
|
return;
|
2012-02-06 03:32:17 +08:00
|
|
|
|
|
|
|
if (action) {
|
2011-11-23 17:03:24 +08:00
|
|
|
carrier = action == 1 ? 1 : 0;
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->flags = flags;
|
2012-02-06 03:32:17 +08:00
|
|
|
} else
|
2013-02-03 18:35:59 +08:00
|
|
|
carrier = carrier_status(ifp);
|
2012-02-06 03:32:17 +08:00
|
|
|
|
2009-10-14 23:16:07 +08:00
|
|
|
if (carrier == -1)
|
|
|
|
syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
|
2013-02-03 18:35:59 +08:00
|
|
|
else if (carrier == 0 || ~ifp->flags & IFF_UP) {
|
|
|
|
if (ifp->carrier != LINK_DOWN) {
|
|
|
|
ifp->carrier = LINK_DOWN;
|
|
|
|
syslog(LOG_INFO, "%s: carrier lost", ifp->name);
|
|
|
|
dhcp_close(ifp);
|
|
|
|
dhcp6_drop(ifp, "EXPIRE6");
|
|
|
|
ipv6rs_drop(ifp);
|
|
|
|
dhcp_drop(ifp, "NOCARRIER");
|
2008-09-04 19:30:11 +08:00
|
|
|
}
|
2013-02-03 18:35:59 +08:00
|
|
|
} else if (carrier == 1 && !(~ifp->flags & IFF_UP)) {
|
|
|
|
if (ifp->carrier != LINK_UP) {
|
|
|
|
ifp->carrier = LINK_UP;
|
|
|
|
syslog(LOG_INFO, "%s: carrier acquired", ifp->name);
|
|
|
|
if (ifp->wireless)
|
|
|
|
getifssid(ifp->name, ifp->ssid);
|
|
|
|
configure_interface(ifp, margc, margv);
|
2013-02-04 06:55:45 +08:00
|
|
|
script_runreason(ifp, "CARRIER");
|
2013-02-03 18:35:59 +08:00
|
|
|
start_interface(ifp);
|
2008-04-21 17:40:14 +08:00
|
|
|
}
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
|
|
|
}
|
2008-04-21 17:40:14 +08:00
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
void
|
2008-09-04 00:49:28 +08:00
|
|
|
start_interface(void *arg)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2013-02-03 18:35:59 +08:00
|
|
|
struct interface *ifp = arg;
|
|
|
|
struct if_options *ifo = ifp->options;
|
2010-09-10 02:27:00 +08:00
|
|
|
int nolease;
|
2008-09-04 00:49:28 +08:00
|
|
|
|
2013-02-03 18:35:59 +08:00
|
|
|
handle_carrier(0, 0, ifp->name);
|
|
|
|
if (ifp->carrier == LINK_DOWN) {
|
|
|
|
syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
|
2008-09-10 01:07:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-12 18:31:51 +08:00
|
|
|
if (options & DHCPCD_IPV6RS && ifo->options & DHCPCD_IPV6RS &&
|
|
|
|
!(ifo->options & DHCPCD_INFORM))
|
2013-02-03 18:35:59 +08:00
|
|
|
ipv6rs_start(ifp);
|
2011-12-15 10:35:47 +08:00
|
|
|
|
2012-11-07 07:40:15 +08:00
|
|
|
if (ifo->options & DHCPCD_IPV6) {
|
|
|
|
if (ifo->options & DHCPCD_INFORM)
|
2013-02-03 18:35:59 +08:00
|
|
|
nolease = dhcp6_start(ifp, 0);
|
2012-11-07 07:40:15 +08:00
|
|
|
else if (!(ifo->options & DHCPCD_IPV6RS))
|
2013-02-03 18:35:59 +08:00
|
|
|
nolease = dhcp6_start(ifp, 1);
|
2012-12-07 17:46:49 +08:00
|
|
|
else
|
|
|
|
nolease = 0;
|
|
|
|
if (nolease == -1)
|
2013-02-03 18:35:59 +08:00
|
|
|
syslog(LOG_ERR, "%s: dhcp6_start: %m", ifp->name);
|
2012-11-07 07:40:15 +08:00
|
|
|
}
|
2012-10-12 18:31:51 +08:00
|
|
|
|
2013-02-02 22:05:55 +08:00
|
|
|
if (ifo->options & DHCPCD_IPV4)
|
2013-02-03 18:35:59 +08:00
|
|
|
dhcp_start(ifp);
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2008-09-04 00:49:28 +08:00
|
|
|
static void
|
2013-02-03 18:35:59 +08:00
|
|
|
init_state(struct interface *ifp, int argc, char **argv)
|
2008-09-04 00:49:28 +08:00
|
|
|
{
|
2013-02-04 06:55:45 +08:00
|
|
|
const char *reason = NULL;
|
2013-02-03 22:52:24 +08:00
|
|
|
|
2013-02-03 18:35:59 +08:00
|
|
|
configure_interface(ifp, argc, argv);
|
2009-01-15 21:31:46 +08:00
|
|
|
if (!(options & DHCPCD_TEST))
|
2013-02-04 06:55:45 +08:00
|
|
|
script_runreason(ifp, "PREINIT");
|
2008-09-04 00:49:28 +08:00
|
|
|
|
2013-02-03 18:35:59 +08:00
|
|
|
if (ifp->options->options & DHCPCD_LINK) {
|
|
|
|
switch (carrier_status(ifp)) {
|
2008-04-24 21:18:59 +08:00
|
|
|
case 0:
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->carrier = LINK_DOWN;
|
2013-02-04 06:55:45 +08:00
|
|
|
reason = "NOCARRIER";
|
2008-04-24 21:18:59 +08:00
|
|
|
break;
|
2008-09-02 21:28:11 +08:00
|
|
|
case 1:
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->carrier = LINK_UP;
|
2013-02-04 06:55:45 +08:00
|
|
|
reason = "CARRIER";
|
2008-09-02 21:28:11 +08:00
|
|
|
break;
|
|
|
|
default:
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->carrier = LINK_UNKNOWN;
|
2009-01-15 21:31:46 +08:00
|
|
|
return;
|
2008-04-24 21:18:59 +08:00
|
|
|
}
|
2013-02-04 06:55:45 +08:00
|
|
|
if (reason && !(options & DHCPCD_TEST))
|
|
|
|
script_runreason(ifp, reason);
|
2008-09-10 01:07:48 +08:00
|
|
|
} else
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->carrier = LINK_UNKNOWN;
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
2008-04-24 21:18:59 +08:00
|
|
|
|
2009-03-20 01:52:12 +08:00
|
|
|
void
|
|
|
|
handle_interface(int action, const char *ifname)
|
2008-09-04 19:30:11 +08:00
|
|
|
{
|
2008-09-04 22:08:14 +08:00
|
|
|
struct interface *ifs, *ifp, *ifn, *ifl = NULL;
|
2009-09-01 15:45:11 +08:00
|
|
|
const char * const argv[] = { ifname };
|
2008-09-04 19:30:11 +08:00
|
|
|
int i;
|
|
|
|
|
2009-03-20 01:52:12 +08:00
|
|
|
if (action == -1) {
|
|
|
|
ifp = find_interface(ifname);
|
|
|
|
if (ifp != NULL)
|
|
|
|
stop_interface(ifp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-04 19:30:11 +08:00
|
|
|
/* If running off an interface list, check it's in it. */
|
|
|
|
if (ifc) {
|
|
|
|
for (i = 0; i < ifc; i++)
|
2008-09-04 22:08:14 +08:00
|
|
|
if (strcmp(ifv[i], ifname) == 0)
|
2008-09-04 19:30:11 +08:00
|
|
|
break;
|
|
|
|
if (i >= ifc)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-01 15:45:11 +08:00
|
|
|
ifs = discover_interfaces(-1, UNCONST(argv));
|
2009-09-01 05:51:17 +08:00
|
|
|
for (ifp = ifs; ifp; ifp = ifp->next) {
|
|
|
|
if (strcmp(ifp->name, ifname) != 0)
|
|
|
|
continue;
|
|
|
|
/* Check if we already have the interface */
|
|
|
|
for (ifn = ifaces; ifn; ifn = ifn->next) {
|
|
|
|
if (strcmp(ifn->name, ifp->name) == 0)
|
|
|
|
break;
|
|
|
|
ifl = ifn;
|
2008-09-04 22:08:14 +08:00
|
|
|
}
|
2009-10-15 15:33:24 +08:00
|
|
|
if (ifn) {
|
|
|
|
/* The flags and hwaddr could have changed */
|
|
|
|
ifn->flags = ifp->flags;
|
|
|
|
ifn->hwlen = ifp->hwlen;
|
|
|
|
if (ifp->hwlen != 0)
|
|
|
|
memcpy(ifn->hwaddr, ifp->hwaddr, ifn->hwlen);
|
|
|
|
} else {
|
|
|
|
if (ifl)
|
|
|
|
ifl->next = ifp;
|
|
|
|
else
|
|
|
|
ifaces = ifp;
|
|
|
|
}
|
2009-09-01 05:51:17 +08:00
|
|
|
init_state(ifp, 0, NULL);
|
|
|
|
start_interface(ifp);
|
2008-09-04 19:30:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-13 04:39:29 +08:00
|
|
|
#ifdef RTM_CHGADDR
|
2010-11-13 00:33:45 +08:00
|
|
|
void
|
|
|
|
handle_hwaddr(const char *ifname, unsigned char *hwaddr, size_t hwlen)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
struct if_options *ifo;
|
2013-02-04 22:12:48 +08:00
|
|
|
struct dhcp_state *state;
|
2010-11-13 00:33:45 +08:00
|
|
|
|
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
|
|
|
if (strcmp(ifp->name, ifname) == 0 && ifp->hwlen <= hwlen) {
|
2013-02-04 22:12:48 +08:00
|
|
|
state = D_STATE(ifp);
|
|
|
|
if (state == NULL)
|
|
|
|
continue;
|
|
|
|
ifo = ifp->options;
|
2010-11-13 00:33:45 +08:00
|
|
|
if (!(ifo->options &
|
|
|
|
(DHCPCD_INFORM | DHCPCD_STATIC | DHCPCD_CLIENTID))
|
2013-02-04 22:12:48 +08:00
|
|
|
&& state->new != NULL &&
|
|
|
|
state->new->cookie == htonl(MAGIC_COOKIE))
|
2010-11-13 00:33:45 +08:00
|
|
|
{
|
|
|
|
syslog(LOG_INFO,
|
|
|
|
"%s: expiring for new hardware address",
|
|
|
|
ifp->name);
|
2013-02-04 22:12:48 +08:00
|
|
|
dhcp_drop(ifp, "EXPIRE");
|
2010-11-13 00:33:45 +08:00
|
|
|
}
|
|
|
|
memcpy(ifp->hwaddr, hwaddr, hwlen);
|
|
|
|
ifp->hwlen = hwlen;
|
|
|
|
if (!(ifo->options &
|
|
|
|
(DHCPCD_INFORM | DHCPCD_STATIC | DHCPCD_CLIENTID)))
|
|
|
|
{
|
|
|
|
syslog(LOG_DEBUG, "%s: using hwaddr %s",
|
|
|
|
ifp->name,
|
|
|
|
hwaddr_ntoa(ifp->hwaddr, ifp->hwlen));
|
2013-02-04 22:12:48 +08:00
|
|
|
state->interval = 0;
|
|
|
|
state->nakoff = 0;
|
2010-11-13 00:33:45 +08:00
|
|
|
start_interface(ifp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(hwaddr);
|
|
|
|
}
|
2010-11-13 04:39:29 +08:00
|
|
|
#endif
|
2010-11-13 00:33:45 +08:00
|
|
|
|
2008-11-10 19:15:27 +08:00
|
|
|
/* ARGSUSED */
|
2008-09-04 19:30:11 +08:00
|
|
|
static void
|
|
|
|
handle_link(_unused void *arg)
|
|
|
|
{
|
2013-02-02 22:05:55 +08:00
|
|
|
|
2009-03-20 06:27:13 +08:00
|
|
|
if (manage_link(linkfd) == -1)
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, "manage_link: %m");
|
2008-09-04 19:30:11 +08:00
|
|
|
}
|
|
|
|
|
2010-06-09 23:26:55 +08:00
|
|
|
static void
|
2013-02-03 18:35:59 +08:00
|
|
|
if_reboot(struct interface *ifp, int argc, char **argv)
|
2010-06-09 23:26:55 +08:00
|
|
|
{
|
2013-02-04 06:55:45 +08:00
|
|
|
int oldopts;
|
|
|
|
|
|
|
|
oldopts = ifp->options->options;
|
2013-02-03 18:35:59 +08:00
|
|
|
configure_interface(ifp, argc, argv);
|
2013-02-04 06:55:45 +08:00
|
|
|
dhcp_reboot(ifp, oldopts);
|
2013-02-03 18:35:59 +08:00
|
|
|
start_interface(ifp);
|
2010-06-09 23:26:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
reconf_reboot(int action, int argc, char **argv, int oi)
|
|
|
|
{
|
|
|
|
struct interface *ifl, *ifn, *ifp, *ifs, *ift;
|
|
|
|
|
|
|
|
ifs = discover_interfaces(argc - oi, argv + oi);
|
|
|
|
if (ifs == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (ifp = ifs; ifp && (ift = ifp->next, 1); ifp = ift) {
|
|
|
|
ifl = NULL;
|
|
|
|
for (ifn = ifaces; ifn; ifn = ifn->next) {
|
|
|
|
if (strcmp(ifn->name, ifp->name) == 0)
|
|
|
|
break;
|
|
|
|
ifl = ifn;
|
|
|
|
}
|
|
|
|
if (ifn) {
|
|
|
|
if (action)
|
2010-06-10 18:38:37 +08:00
|
|
|
if_reboot(ifn, argc, argv);
|
2013-02-04 06:55:45 +08:00
|
|
|
else
|
2013-02-02 22:05:55 +08:00
|
|
|
ipv4_applyaddr(ifn);
|
2010-06-09 23:26:55 +08:00
|
|
|
free_interface(ifp);
|
|
|
|
} else {
|
|
|
|
ifp->next = NULL;
|
|
|
|
init_state(ifp, argc, argv);
|
|
|
|
start_interface(ifp);
|
|
|
|
if (ifl)
|
|
|
|
ifl->next = ifp;
|
|
|
|
else
|
|
|
|
ifaces = ifp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort_interfaces();
|
|
|
|
}
|
|
|
|
|
2012-11-11 00:38:52 +08:00
|
|
|
void
|
|
|
|
handle_signal(int sig)
|
2008-09-02 21:28:11 +08:00
|
|
|
{
|
2012-04-01 15:38:52 +08:00
|
|
|
struct interface *ifp;
|
2010-06-09 23:26:55 +08:00
|
|
|
struct if_options *ifo;
|
2012-04-01 15:38:52 +08:00
|
|
|
int do_release, i;
|
2008-04-24 21:18:59 +08:00
|
|
|
|
2012-04-01 15:38:52 +08:00
|
|
|
do_release = 0;
|
2008-09-02 21:28:11 +08:00
|
|
|
switch (sig) {
|
|
|
|
case SIGINT:
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_INFO, "received SIGINT, stopping");
|
2008-09-02 21:28:11 +08:00
|
|
|
break;
|
|
|
|
case SIGTERM:
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_INFO, "received SIGTERM, stopping");
|
2008-09-02 21:28:11 +08:00
|
|
|
break;
|
2008-09-04 00:49:28 +08:00
|
|
|
case SIGALRM:
|
2010-06-09 23:26:55 +08:00
|
|
|
syslog(LOG_INFO, "received SIGALRM, rebinding");
|
2010-06-10 00:51:40 +08:00
|
|
|
for (i = 0; i < ifac; i++)
|
|
|
|
free(ifav[i]);
|
|
|
|
free(ifav);
|
|
|
|
ifav = NULL;
|
|
|
|
ifac = 0;
|
|
|
|
for (i = 0; i < ifdc; i++)
|
|
|
|
free(ifdv[i]);
|
|
|
|
free(ifdv);
|
|
|
|
ifdc = 0;
|
|
|
|
ifdv = NULL;
|
2010-06-09 23:26:55 +08:00
|
|
|
ifo = read_config(cffile, NULL, NULL, NULL);
|
2010-06-10 00:51:40 +08:00
|
|
|
add_options(ifo, margc, margv);
|
2010-06-09 23:26:55 +08:00
|
|
|
/* We need to preserve these two options. */
|
|
|
|
if (options & DHCPCD_MASTER)
|
|
|
|
ifo->options |= DHCPCD_MASTER;
|
|
|
|
if (options & DHCPCD_DAEMONISED)
|
|
|
|
ifo->options |= DHCPCD_DAEMONISED;
|
|
|
|
options = ifo->options;
|
|
|
|
free_options(ifo);
|
2012-03-28 00:47:43 +08:00
|
|
|
reconf_reboot(1, ifc, ifv, 0);
|
2008-09-15 23:23:46 +08:00
|
|
|
return;
|
2008-09-04 00:49:28 +08:00
|
|
|
case SIGHUP:
|
2010-06-09 23:26:55 +08:00
|
|
|
syslog(LOG_INFO, "received SIGHUP, releasing");
|
2008-09-04 00:49:28 +08:00
|
|
|
do_release = 1;
|
|
|
|
break;
|
2009-03-20 18:21:12 +08:00
|
|
|
case SIGUSR1:
|
|
|
|
syslog(LOG_INFO, "received SIGUSR, reconfiguring");
|
2010-06-09 23:26:55 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
2013-02-04 06:55:45 +08:00
|
|
|
ipv4_applyaddr(ifp);
|
2009-03-20 18:33:09 +08:00
|
|
|
return;
|
2009-01-21 00:33:11 +08:00
|
|
|
case SIGPIPE:
|
|
|
|
syslog(LOG_WARNING, "received SIGPIPE");
|
|
|
|
return;
|
2008-09-02 21:28:11 +08:00
|
|
|
default:
|
2008-09-15 23:23:46 +08:00
|
|
|
syslog(LOG_ERR,
|
2009-02-12 01:56:22 +08:00
|
|
|
"received signal %d, but don't know what to do with it",
|
|
|
|
sig);
|
2008-09-02 21:28:11 +08:00
|
|
|
return;
|
|
|
|
}
|
2008-04-24 21:18:59 +08:00
|
|
|
|
2009-07-12 02:54:43 +08:00
|
|
|
if (options & DHCPCD_TEST)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
2011-12-15 10:35:47 +08:00
|
|
|
/* As drop_dhcp could re-arrange the order, we do it like this. */
|
2008-09-10 01:07:48 +08:00
|
|
|
for (;;) {
|
2008-09-12 06:55:27 +08:00
|
|
|
/* Be sane and drop the last config first */
|
2010-06-09 23:26:55 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next) {
|
|
|
|
if (ifp->next == NULL)
|
2009-01-21 00:33:11 +08:00
|
|
|
break;
|
2008-10-19 00:41:19 +08:00
|
|
|
}
|
2010-06-09 23:26:55 +08:00
|
|
|
if (ifp == NULL)
|
2009-01-21 00:33:11 +08:00
|
|
|
break;
|
2010-06-09 23:26:55 +08:00
|
|
|
if (ifp->carrier != LINK_DOWN &&
|
2009-01-21 00:33:11 +08:00
|
|
|
(do_release ||
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->options->options & DHCPCD_RELEASE))
|
2013-02-02 22:05:55 +08:00
|
|
|
dhcp_release(ifp);
|
2010-06-09 23:26:55 +08:00
|
|
|
stop_interface(ifp);
|
2008-04-24 21:18:59 +08:00
|
|
|
}
|
2008-09-02 21:28:11 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2008-04-24 21:18:59 +08:00
|
|
|
|
2008-09-04 00:49:28 +08:00
|
|
|
int
|
2009-01-13 00:39:01 +08:00
|
|
|
handle_args(struct fd_list *fd, int argc, char **argv)
|
2008-09-04 00:49:28 +08:00
|
|
|
{
|
2010-06-09 23:26:55 +08:00
|
|
|
struct interface *ifp;
|
2012-04-01 15:38:52 +08:00
|
|
|
int do_exit = 0, do_release = 0, do_reboot = 0;
|
2009-03-20 18:21:12 +08:00
|
|
|
int opt, oi = 0;
|
2009-01-15 22:22:40 +08:00
|
|
|
ssize_t len;
|
2009-02-06 05:06:57 +08:00
|
|
|
size_t l;
|
2009-01-14 01:04:28 +08:00
|
|
|
struct iovec iov[2];
|
2009-02-06 05:06:57 +08:00
|
|
|
char *tmp, *p;
|
2008-09-04 00:49:28 +08:00
|
|
|
|
2009-01-13 00:39:01 +08:00
|
|
|
if (fd != NULL) {
|
2009-01-14 01:04:28 +08:00
|
|
|
/* Special commands for our control socket */
|
2009-01-13 00:39:01 +08:00
|
|
|
if (strcmp(*argv, "--version") == 0) {
|
2009-01-15 22:22:40 +08:00
|
|
|
len = strlen(VERSION) + 1;
|
|
|
|
iov[0].iov_base = &len;
|
2009-01-14 02:03:12 +08:00
|
|
|
iov[0].iov_len = sizeof(ssize_t);
|
|
|
|
iov[1].iov_base = UNCONST(VERSION);
|
2009-01-15 22:22:40 +08:00
|
|
|
iov[1].iov_len = len;
|
2009-07-04 08:58:03 +08:00
|
|
|
if (writev(fd->fd, iov, 2) == -1) {
|
|
|
|
syslog(LOG_ERR, "writev: %m");
|
|
|
|
return -1;
|
|
|
|
}
|
2009-01-13 00:39:01 +08:00
|
|
|
return 0;
|
2009-02-13 23:39:34 +08:00
|
|
|
} else if (strcmp(*argv, "--getconfigfile") == 0) {
|
|
|
|
len = strlen(cffile ? cffile : CONFIG) + 1;
|
|
|
|
iov[0].iov_base = &len;
|
|
|
|
iov[0].iov_len = sizeof(ssize_t);
|
|
|
|
iov[1].iov_base = cffile ? cffile : UNCONST(CONFIG);
|
|
|
|
iov[1].iov_len = len;
|
2009-07-04 08:58:03 +08:00
|
|
|
if (writev(fd->fd, iov, 2) == -1) {
|
|
|
|
syslog(LOG_ERR, "writev: %m");
|
|
|
|
return -1;
|
|
|
|
}
|
2009-02-13 23:39:34 +08:00
|
|
|
return 0;
|
2009-01-14 01:04:28 +08:00
|
|
|
} else if (strcmp(*argv, "--getinterfaces") == 0) {
|
2009-01-15 22:22:40 +08:00
|
|
|
len = 0;
|
2009-01-17 08:43:08 +08:00
|
|
|
if (argc == 1) {
|
2012-02-03 00:22:40 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next) {
|
2009-01-15 22:22:40 +08:00
|
|
|
len++;
|
2012-10-13 03:10:04 +08:00
|
|
|
if (D6_STATE_RUNNING(ifp))
|
|
|
|
len++;
|
2012-07-06 00:37:41 +08:00
|
|
|
if (ipv6rs_has_ra(ifp))
|
2012-02-03 00:22:40 +08:00
|
|
|
len++;
|
|
|
|
}
|
2009-01-29 21:01:29 +08:00
|
|
|
len = write(fd->fd, &len, sizeof(len));
|
|
|
|
if (len != sizeof(len))
|
|
|
|
return -1;
|
2009-01-15 22:22:40 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
|
|
|
send_interface(fd->fd, ifp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
opt = 0;
|
|
|
|
while (argv[++opt] != NULL) {
|
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
2012-02-03 00:22:40 +08:00
|
|
|
if (strcmp(argv[opt], ifp->name) == 0) {
|
2009-01-15 22:22:40 +08:00
|
|
|
len++;
|
2012-10-13 03:10:04 +08:00
|
|
|
if (D6_STATE_RUNNING(ifp))
|
|
|
|
len++;
|
2012-07-06 00:37:41 +08:00
|
|
|
if (ipv6rs_has_ra(ifp))
|
2012-02-03 00:22:40 +08:00
|
|
|
len++;
|
|
|
|
}
|
2009-01-15 22:22:40 +08:00
|
|
|
}
|
2009-01-29 21:01:29 +08:00
|
|
|
len = write(fd->fd, &len, sizeof(len));
|
|
|
|
if (len != sizeof(len))
|
|
|
|
return -1;
|
2009-01-15 22:22:40 +08:00
|
|
|
opt = 0;
|
|
|
|
while (argv[++opt] != NULL) {
|
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
|
|
|
if (strcmp(argv[opt], ifp->name) == 0)
|
|
|
|
send_interface(fd->fd, ifp);
|
2009-01-13 00:39:01 +08:00
|
|
|
}
|
2009-01-14 01:04:28 +08:00
|
|
|
return 0;
|
2009-01-13 00:39:01 +08:00
|
|
|
} else if (strcmp(*argv, "--listen") == 0) {
|
|
|
|
fd->listener = 1;
|
2009-01-05 16:20:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-06 05:06:57 +08:00
|
|
|
/* Log the command */
|
|
|
|
len = 0;
|
|
|
|
for (opt = 0; opt < argc; opt++)
|
|
|
|
len += strlen(argv[opt]) + 1;
|
|
|
|
tmp = p = xmalloc(len + 1);
|
|
|
|
for (opt = 0; opt < argc; opt++) {
|
|
|
|
l = strlen(argv[opt]);
|
|
|
|
strlcpy(p, argv[opt], l + 1);
|
|
|
|
p += l;
|
|
|
|
*p++ = ' ';
|
|
|
|
}
|
|
|
|
*--p = '\0';
|
|
|
|
syslog(LOG_INFO, "control command: %s", tmp);
|
|
|
|
free(tmp);
|
|
|
|
|
2008-09-04 00:49:28 +08:00
|
|
|
optind = 0;
|
|
|
|
while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
|
|
|
|
{
|
|
|
|
switch (opt) {
|
2009-07-26 07:22:10 +08:00
|
|
|
case 'g':
|
2012-04-01 15:38:52 +08:00
|
|
|
/* Assumed if below not set */
|
2009-03-20 18:21:12 +08:00
|
|
|
break;
|
2008-09-04 00:49:28 +08:00
|
|
|
case 'k':
|
|
|
|
do_release = 1;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
do_reboot = 1;
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
do_exit = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-05 23:50:14 +08:00
|
|
|
/* We need at least one interface */
|
2008-09-04 00:49:28 +08:00
|
|
|
if (optind == argc) {
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, "handle_args: no interface");
|
2008-09-04 00:49:28 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-10-06 16:37:02 +08:00
|
|
|
if (do_release || do_exit) {
|
2008-09-04 16:27:38 +08:00
|
|
|
for (oi = optind; oi < argc; oi++) {
|
2008-09-12 06:55:27 +08:00
|
|
|
for (ifp = ifaces; ifp; ifp = ifp->next)
|
2008-09-04 16:27:38 +08:00
|
|
|
if (strcmp(ifp->name, argv[oi]) == 0)
|
|
|
|
break;
|
|
|
|
if (!ifp)
|
|
|
|
continue;
|
|
|
|
if (do_release)
|
2013-02-03 18:35:59 +08:00
|
|
|
ifp->options->options |= DHCPCD_RELEASE;
|
|
|
|
if (ifp->options->options & DHCPCD_RELEASE &&
|
2009-01-21 00:33:11 +08:00
|
|
|
ifp->carrier != LINK_DOWN)
|
2013-02-02 22:05:55 +08:00
|
|
|
dhcp_release(ifp);
|
2009-01-21 00:33:11 +08:00
|
|
|
stop_interface(ifp);
|
2008-09-04 00:49:28 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-09 23:26:55 +08:00
|
|
|
reconf_reboot(do_reboot, argc, argv, optind);
|
2008-09-04 00:49:28 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
2009-02-25 03:17:19 +08:00
|
|
|
struct interface *iface;
|
2012-10-12 19:26:20 +08:00
|
|
|
uint16_t family = 0;
|
2012-11-11 00:38:52 +08:00
|
|
|
int opt, oi = 0, sig = 0, i, control_fd;
|
2008-09-05 22:16:53 +08:00
|
|
|
size_t len;
|
2008-09-02 21:28:11 +08:00
|
|
|
pid_t pid;
|
|
|
|
struct timespec ts;
|
2012-10-09 21:20:50 +08:00
|
|
|
struct utsname utn;
|
|
|
|
const char *platform;
|
2008-09-02 21:28:11 +08:00
|
|
|
|
|
|
|
closefrom(3);
|
2010-04-30 11:02:29 +08:00
|
|
|
openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
|
2008-09-06 02:24:34 +08:00
|
|
|
setlogmask(LOG_UPTO(LOG_INFO));
|
2008-09-02 21:28:11 +08:00
|
|
|
|
|
|
|
/* Test for --help and --version */
|
|
|
|
if (argc > 1) {
|
|
|
|
if (strcmp(argv[1], "--help") == 0) {
|
2008-04-21 17:40:14 +08:00
|
|
|
usage();
|
2008-09-02 21:28:11 +08:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
} else if (strcmp(argv[1], "--version") == 0) {
|
|
|
|
printf(""PACKAGE" "VERSION"\n%s\n", copyright);
|
|
|
|
exit(EXIT_SUCCESS);
|
2008-04-19 07:12:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-09 21:20:50 +08:00
|
|
|
platform = hardware_platform();
|
|
|
|
if (uname(&utn) == 0)
|
|
|
|
snprintf(vendor, VENDORCLASSID_MAX_LEN,
|
|
|
|
"%s-%s:%s-%s:%s%s%s", PACKAGE, VERSION,
|
|
|
|
utn.sysname, utn.release, utn.machine,
|
|
|
|
platform ? ":" : "", platform ? platform : "");
|
|
|
|
else
|
|
|
|
snprintf(vendor, VENDORCLASSID_MAX_LEN,
|
|
|
|
"%s-%s", PACKAGE, VERSION);
|
|
|
|
|
2008-09-11 17:38:02 +08:00
|
|
|
i = 0;
|
2008-09-02 21:28:11 +08:00
|
|
|
while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
|
2007-05-11 18:51:32 +08:00
|
|
|
{
|
2007-05-14 21:34:36 +08:00
|
|
|
switch (opt) {
|
2012-10-12 18:31:51 +08:00
|
|
|
case '4':
|
|
|
|
family = AF_INET;
|
|
|
|
break;
|
|
|
|
case '6':
|
|
|
|
family = AF_INET6;
|
|
|
|
break;
|
2008-03-21 00:47:51 +08:00
|
|
|
case 'f':
|
2008-09-05 21:28:44 +08:00
|
|
|
cffile = optarg;
|
2008-03-21 00:47:51 +08:00
|
|
|
break;
|
2009-07-26 07:22:10 +08:00
|
|
|
case 'g':
|
|
|
|
sig = SIGUSR1;
|
|
|
|
break;
|
2008-09-04 00:49:28 +08:00
|
|
|
case 'k':
|
|
|
|
sig = SIGHUP;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
sig = SIGALRM;
|
|
|
|
break;
|
2008-03-21 00:47:51 +08:00
|
|
|
case 'x':
|
|
|
|
sig = SIGTERM;
|
|
|
|
break;
|
2008-04-19 07:12:44 +08:00
|
|
|
case 'T':
|
2008-09-11 17:38:02 +08:00
|
|
|
i = 1;
|
2008-03-21 00:47:51 +08:00
|
|
|
break;
|
2010-08-24 17:16:07 +08:00
|
|
|
case 'U':
|
|
|
|
i = 2;
|
|
|
|
break;
|
2008-09-02 21:28:11 +08:00
|
|
|
case 'V':
|
2012-10-12 18:31:51 +08:00
|
|
|
printf("Interface options:\n");
|
|
|
|
if_printoptions();
|
2013-02-04 21:30:35 +08:00
|
|
|
#ifdef INET
|
2012-10-12 18:31:51 +08:00
|
|
|
if (family == 0 || family == AF_INET) {
|
|
|
|
printf("\nDHCPv4 options:\n");
|
2013-02-04 21:30:35 +08:00
|
|
|
dhcp_printoptions();
|
2012-10-12 18:31:51 +08:00
|
|
|
}
|
2013-02-04 21:30:35 +08:00
|
|
|
#endif
|
|
|
|
#ifdef INET6
|
2012-10-12 18:31:51 +08:00
|
|
|
if (family == 0 || family == AF_INET6) {
|
|
|
|
printf("\nDHCPv6 options:\n");
|
|
|
|
dhcp6_printoptions();
|
|
|
|
}
|
2013-02-04 21:30:35 +08:00
|
|
|
#endif
|
2008-09-02 21:28:11 +08:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
case '?':
|
|
|
|
usage();
|
|
|
|
exit(EXIT_FAILURE);
|
2007-04-11 21:18:33 +08:00
|
|
|
}
|
2007-05-11 18:51:32 +08:00
|
|
|
}
|
2008-05-13 05:03:38 +08:00
|
|
|
|
2009-01-02 04:51:04 +08:00
|
|
|
margv = argv;
|
|
|
|
margc = argc;
|
2010-08-24 17:34:21 +08:00
|
|
|
if_options = read_config(cffile, NULL, NULL, NULL);
|
|
|
|
opt = add_options(if_options, argc, argv);
|
2008-09-02 21:28:11 +08:00
|
|
|
if (opt != 1) {
|
|
|
|
if (opt == 0)
|
|
|
|
usage();
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2010-08-24 17:34:21 +08:00
|
|
|
options = if_options->options;
|
2009-07-12 02:54:43 +08:00
|
|
|
if (i != 0) {
|
2010-08-24 17:16:07 +08:00
|
|
|
if (i == 1)
|
|
|
|
options |= DHCPCD_TEST;
|
|
|
|
else
|
|
|
|
options |= DHCPCD_DUMPLEASE;
|
|
|
|
options |= DHCPCD_PERSISTENT;
|
2009-07-12 02:54:43 +08:00
|
|
|
options &= ~DHCPCD_DAEMONISE;
|
|
|
|
}
|
|
|
|
|
2008-09-11 16:28:39 +08:00
|
|
|
#ifdef THERE_IS_NO_FORK
|
|
|
|
options &= ~DHCPCD_DAEMONISE;
|
|
|
|
#endif
|
|
|
|
|
2009-02-24 07:52:21 +08:00
|
|
|
if (options & DHCPCD_DEBUG)
|
|
|
|
setlogmask(LOG_UPTO(LOG_DEBUG));
|
2010-04-27 18:46:44 +08:00
|
|
|
if (options & DHCPCD_QUIET)
|
2009-11-20 05:31:41 +08:00
|
|
|
close(STDERR_FILENO);
|
2008-09-11 16:28:39 +08:00
|
|
|
|
2010-08-24 17:16:07 +08:00
|
|
|
if (!(options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
|
2009-07-12 02:54:43 +08:00
|
|
|
/* If we have any other args, we should run as a single dhcpcd
|
|
|
|
* instance for that interface. */
|
|
|
|
len = strlen(PIDFILE) + IF_NAMESIZE + 2;
|
|
|
|
pidfile = xmalloc(len);
|
|
|
|
if (optind == argc - 1)
|
|
|
|
snprintf(pidfile, len, PIDFILE, "-", argv[optind]);
|
|
|
|
else {
|
|
|
|
snprintf(pidfile, len, PIDFILE, "", "");
|
|
|
|
options |= DHCPCD_MASTER;
|
|
|
|
}
|
2008-09-04 00:49:28 +08:00
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2009-01-29 21:01:29 +08:00
|
|
|
if (chdir("/") == -1)
|
2009-01-29 21:18:57 +08:00
|
|
|
syslog(LOG_ERR, "chdir `/': %m");
|
2008-09-02 21:28:11 +08:00
|
|
|
atexit(cleanup);
|
2008-08-15 00:16:06 +08:00
|
|
|
|
2010-08-24 17:16:07 +08:00
|
|
|
if (options & DHCPCD_DUMPLEASE) {
|
|
|
|
if (optind != argc - 1) {
|
|
|
|
syslog(LOG_ERR, "dumplease requires an interface");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2013-02-04 06:55:45 +08:00
|
|
|
if (dhcp_dump(argv[optind]) == -1)
|
2010-08-24 17:16:07 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2010-08-24 21:35:15 +08:00
|
|
|
if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) {
|
2012-11-13 18:17:19 +08:00
|
|
|
control_fd = control_open();
|
2008-09-04 00:49:28 +08:00
|
|
|
if (control_fd != -1) {
|
2009-02-12 01:56:22 +08:00
|
|
|
syslog(LOG_INFO,
|
|
|
|
"sending commands to master dhcpcd process");
|
2012-11-13 18:17:19 +08:00
|
|
|
i = control_send(argc, argv);
|
2008-09-04 00:49:28 +08:00
|
|
|
if (i > 0) {
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_DEBUG, "send OK");
|
2008-09-04 00:49:28 +08:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
} else {
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, "failed to send commands");
|
2008-09-04 00:49:28 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2008-09-05 21:28:44 +08:00
|
|
|
} else {
|
2008-09-05 23:46:02 +08:00
|
|
|
if (errno != ENOENT)
|
2012-11-13 18:17:19 +08:00
|
|
|
syslog(LOG_ERR, "control_open: %m");
|
2008-09-04 00:49:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (geteuid())
|
2009-02-12 01:56:22 +08:00
|
|
|
syslog(LOG_WARNING,
|
|
|
|
PACKAGE " will not work correctly unless run as root");
|
2008-09-04 00:49:28 +08:00
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
if (sig != 0) {
|
|
|
|
pid = read_pid();
|
2007-07-12 20:52:27 +08:00
|
|
|
if (pid != 0)
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_INFO, "sending signal %d to pid %d",
|
2009-02-12 01:56:22 +08:00
|
|
|
sig, pid);
|
2009-05-09 22:15:31 +08:00
|
|
|
if (pid == 0 || kill(pid, sig) != 0) {
|
2012-07-06 00:37:41 +08:00
|
|
|
if (sig != SIGALRM && errno != EPERM)
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, ""PACKAGE" not running");
|
2009-10-14 23:16:07 +08:00
|
|
|
if (pid != 0 && errno != ESRCH) {
|
|
|
|
syslog(LOG_ERR, "kill: %m");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2008-09-02 21:28:11 +08:00
|
|
|
unlink(pidfile);
|
2009-05-09 22:15:31 +08:00
|
|
|
if (sig != SIGALRM)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
} else {
|
2011-12-18 20:11:08 +08:00
|
|
|
if (sig == SIGALRM || sig == SIGUSR1)
|
2008-09-02 21:28:11 +08:00
|
|
|
exit(EXIT_SUCCESS);
|
2009-05-09 22:15:31 +08:00
|
|
|
/* Spin until it exits */
|
|
|
|
syslog(LOG_INFO, "waiting for pid %d to exit", pid);
|
|
|
|
ts.tv_sec = 0;
|
|
|
|
ts.tv_nsec = 100000000; /* 10th of a second */
|
|
|
|
for(i = 0; i < 100; i++) {
|
|
|
|
nanosleep(&ts, NULL);
|
|
|
|
if (read_pid() == 0)
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
syslog(LOG_ERR, "pid %d failed to exit", pid);
|
|
|
|
exit(EXIT_FAILURE);
|
2008-09-02 21:28:11 +08:00
|
|
|
}
|
2007-05-13 20:28:54 +08:00
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2008-09-05 15:22:03 +08:00
|
|
|
if (!(options & DHCPCD_TEST)) {
|
2008-09-02 21:28:11 +08:00
|
|
|
if ((pid = read_pid()) > 0 &&
|
2008-03-21 00:47:51 +08:00
|
|
|
kill(pid, 0) == 0)
|
2008-01-17 00:38:47 +08:00
|
|
|
{
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, ""PACKAGE
|
2009-02-12 01:56:22 +08:00
|
|
|
" already running on pid %d (%s)",
|
|
|
|
pid, pidfile);
|
2008-09-02 21:28:11 +08:00
|
|
|
exit(EXIT_FAILURE);
|
2007-07-12 20:52:27 +08:00
|
|
|
}
|
|
|
|
|
2009-07-09 03:22:31 +08:00
|
|
|
/* Ensure we have the needed directories */
|
2012-01-30 01:28:05 +08:00
|
|
|
if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST)
|
2009-07-09 03:22:31 +08:00
|
|
|
syslog(LOG_ERR, "mkdir `%s': %m", RUNDIR);
|
2012-01-30 01:28:05 +08:00
|
|
|
if (mkdir(DBDIR, 0755) == -1 && errno != EEXIST)
|
2009-07-09 03:22:31 +08:00
|
|
|
syslog(LOG_ERR, "mkdir `%s': %m", DBDIR);
|
|
|
|
|
2008-09-02 21:28:11 +08:00
|
|
|
pidfd = open(pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
|
2012-01-30 01:28:05 +08:00
|
|
|
if (pidfd == -1)
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, "open `%s': %m", pidfile);
|
2012-01-30 01:28:05 +08:00
|
|
|
else {
|
|
|
|
/* Lock the file so that only one instance of dhcpcd
|
|
|
|
* runs on an interface */
|
|
|
|
if (flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
|
|
|
|
syslog(LOG_ERR, "flock `%s': %m", pidfile);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
if (set_cloexec(pidfd) == -1)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
writepid(pidfd, getpid());
|
2007-07-12 20:52:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_INFO, "version " VERSION " starting");
|
2012-11-10 16:44:48 +08:00
|
|
|
options |= DHCPCD_STARTED;
|
2008-07-01 00:02:56 +08:00
|
|
|
|
2012-11-01 22:46:05 +08:00
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
eloop_init();
|
|
|
|
#endif
|
|
|
|
|
2012-11-11 00:38:52 +08:00
|
|
|
/* This blocks all signals we're interested in.
|
|
|
|
* eloop uses pselect(2) so that the signals are unblocked
|
|
|
|
* when we're testing fd's.
|
|
|
|
* This allows us to ensure a consistent state is maintained
|
|
|
|
* regardless of when we are interrupted .*/
|
|
|
|
if (signal_setup(handle_signal, &dhcpcd_sigset) == -1) {
|
|
|
|
syslog(LOG_ERR, "signal_setup: %m");
|
2008-09-02 21:28:11 +08:00
|
|
|
exit(EXIT_FAILURE);
|
2012-11-11 00:38:52 +08:00
|
|
|
}
|
2007-09-04 20:48:40 +08:00
|
|
|
|
2008-09-05 15:22:03 +08:00
|
|
|
if (options & DHCPCD_MASTER) {
|
2012-11-13 18:17:19 +08:00
|
|
|
if (control_start() == -1)
|
|
|
|
syslog(LOG_ERR, "control_start: %m");
|
2008-09-04 00:49:28 +08:00
|
|
|
}
|
|
|
|
|
2013-02-04 19:03:08 +08:00
|
|
|
if (open_sockets() == -1) {
|
|
|
|
syslog(LOG_ERR, "open_sockets: %m");
|
2009-01-28 03:40:05 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2010-08-24 17:34:21 +08:00
|
|
|
if (if_options->options & DHCPCD_LINK) {
|
2008-09-02 21:28:11 +08:00
|
|
|
linkfd = open_link_socket();
|
|
|
|
if (linkfd == -1)
|
2008-09-06 02:24:34 +08:00
|
|
|
syslog(LOG_ERR, "open_link_socket: %m");
|
2008-09-02 21:28:11 +08:00
|
|
|
else
|
2012-11-13 19:25:51 +08:00
|
|
|
eloop_event_add(linkfd, handle_link, NULL);
|
2007-10-21 00:58:13 +08:00
|
|
|
}
|
2008-09-02 21:28:11 +08:00
|
|
|
|
2011-12-15 10:35:47 +08:00
|
|
|
#if 0
|
|
|
|
if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) {
|
|
|
|
syslog(LOG_ERR, "ipv6rs: %m");
|
|
|
|
options &= ~DHCPCD_IPV6RS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-11-07 07:40:15 +08:00
|
|
|
if (options & DHCPCD_IPV6 && ipv6_init() == -1) {
|
|
|
|
options &= ~DHCPCD_IPV6;
|
|
|
|
syslog(LOG_ERR, "ipv6_init: %m");
|
|
|
|
}
|
2012-03-05 18:04:26 +08:00
|
|
|
if (options & DHCPCD_IPV6RS && !check_ipv6(NULL))
|
2012-02-04 23:15:25 +08:00
|
|
|
options &= ~DHCPCD_IPV6RS;
|
2013-02-04 21:30:35 +08:00
|
|
|
if (options & DHCPCD_IPV6RS)
|
|
|
|
ipv6rs_init();
|
2011-12-15 10:35:47 +08:00
|
|
|
|
2009-02-25 15:52:07 +08:00
|
|
|
ifc = argc - optind;
|
|
|
|
ifv = argv + optind;
|
2008-09-02 21:28:11 +08:00
|
|
|
|
2009-10-25 18:56:54 +08:00
|
|
|
/* 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_WAITIP;
|
|
|
|
|
2008-09-04 19:30:11 +08:00
|
|
|
ifaces = discover_interfaces(ifc, ifv);
|
2008-11-15 04:38:40 +08:00
|
|
|
for (i = 0; i < ifc; i++) {
|
|
|
|
for (iface = ifaces; iface; iface = iface->next)
|
|
|
|
if (strcmp(iface->name, ifv[i]) == 0)
|
|
|
|
break;
|
|
|
|
if (!iface)
|
2008-11-15 19:24:26 +08:00
|
|
|
syslog(LOG_ERR, "%s: interface not found or invalid",
|
2009-02-12 01:56:22 +08:00
|
|
|
ifv[i]);
|
2008-11-15 04:38:40 +08:00
|
|
|
}
|
|
|
|
if (!ifaces) {
|
|
|
|
if (ifc == 0)
|
|
|
|
syslog(LOG_ERR, "no valid interfaces found");
|
2009-10-10 03:24:22 +08:00
|
|
|
else
|
|
|
|
exit(EXIT_FAILURE);
|
2009-02-25 15:52:07 +08:00
|
|
|
if (!(options & DHCPCD_LINK)) {
|
2009-10-14 23:16:07 +08:00
|
|
|
syslog(LOG_ERR,
|
|
|
|
"aborting as link detection is disabled");
|
2008-11-15 19:24:26 +08:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2008-09-04 19:30:11 +08:00
|
|
|
}
|
2008-11-15 04:38:40 +08:00
|
|
|
|
2009-10-14 23:16:07 +08:00
|
|
|
if (options & DHCPCD_BACKGROUND)
|
|
|
|
daemonise();
|
|
|
|
|
|
|
|
opt = 0;
|
|
|
|
for (iface = ifaces; iface; iface = iface->next) {
|
2008-09-10 01:07:48 +08:00
|
|
|
init_state(iface, argc, argv);
|
2009-10-14 23:16:07 +08:00
|
|
|
if (iface->carrier != LINK_DOWN)
|
|
|
|
opt = 1;
|
|
|
|
}
|
2009-11-20 23:14:27 +08:00
|
|
|
|
|
|
|
if (!(options & DHCPCD_BACKGROUND)) {
|
|
|
|
/* If we don't have a carrier, we may have to wait for a second
|
2012-01-30 01:28:05 +08:00
|
|
|
* before one becomes available if we brought an interface up */
|
2009-11-20 23:14:27 +08:00
|
|
|
if (opt == 0 &&
|
|
|
|
options & DHCPCD_LINK &&
|
|
|
|
options & DHCPCD_WAITUP &&
|
|
|
|
!(options & DHCPCD_WAITIP))
|
|
|
|
{
|
|
|
|
ts.tv_sec = 1;
|
|
|
|
ts.tv_nsec = 0;
|
|
|
|
nanosleep(&ts, NULL);
|
|
|
|
for (iface = ifaces; iface; iface = iface->next) {
|
2011-11-23 17:03:24 +08:00
|
|
|
handle_carrier(0, 0, iface->name);
|
2009-11-20 23:14:27 +08:00
|
|
|
if (iface->carrier != LINK_DOWN) {
|
|
|
|
opt = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-29 18:36:17 +08:00
|
|
|
if (options & DHCPCD_MASTER)
|
|
|
|
i = if_options->timeout;
|
2013-02-03 18:35:59 +08:00
|
|
|
else if (ifaces)
|
|
|
|
i = ifaces->options->timeout;
|
2011-03-29 18:36:17 +08:00
|
|
|
else
|
2013-02-03 18:35:59 +08:00
|
|
|
i = 0;
|
2009-11-20 23:14:27 +08:00
|
|
|
if (opt == 0 &&
|
|
|
|
options & DHCPCD_LINK &&
|
|
|
|
!(options & DHCPCD_WAITIP))
|
|
|
|
{
|
|
|
|
syslog(LOG_WARNING, "no interfaces have a carrier");
|
|
|
|
daemonise();
|
2011-03-29 18:36:17 +08:00
|
|
|
} else if (i > 0) {
|
2009-11-20 23:14:27 +08:00
|
|
|
if (options & DHCPCD_IPV4LL)
|
|
|
|
options |= DHCPCD_TIMEOUT_IPV4LL;
|
2012-11-13 19:25:51 +08:00
|
|
|
eloop_timeout_add_sec(i, handle_exit_timeout, NULL);
|
2009-11-20 23:14:27 +08:00
|
|
|
}
|
2009-10-14 23:16:07 +08:00
|
|
|
}
|
2010-08-24 17:34:21 +08:00
|
|
|
free_options(if_options);
|
|
|
|
if_options = NULL;
|
2009-10-14 23:16:07 +08:00
|
|
|
|
2008-09-10 01:07:48 +08:00
|
|
|
sort_interfaces();
|
2009-02-25 03:17:19 +08:00
|
|
|
for (iface = ifaces; iface; iface = iface->next)
|
2012-11-13 19:25:51 +08:00
|
|
|
eloop_timeout_add_sec(0, start_interface, iface);
|
2009-02-20 05:15:25 +08:00
|
|
|
|
2012-11-13 19:25:51 +08:00
|
|
|
eloop_start(&dhcpcd_sigset);
|
2008-11-24 19:21:31 +08:00
|
|
|
exit(EXIT_SUCCESS);
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|