This commit is contained in:
roy 2014-03-14 11:31:11 +00:00
parent 167f6f25d6
commit 083b63d1f4
7 changed files with 221 additions and 519 deletions

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp.c,v 1.11 2014/03/01 11:04:21 roy Exp $");
__RCSID("$NetBSD: dhcp.c,v 1.12 2014/03/14 11:31:11 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -1064,8 +1064,12 @@ read_lease(struct interface *ifp)
free(dhcp);
return NULL;
}
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
ifp->name, state->auth.token->secretid);
if (state->auth.token)
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
ifp->name, state->auth.token->secretid);
else
syslog(LOG_DEBUG, "%s: accepted reconfigure key",
ifp->name);
}
return dhcp;
@ -1347,7 +1351,7 @@ dhcp_close(struct interface *ifp)
state->raw_fd = -1;
}
if (state->udp_fd != -1) {
/* we don't listen to events on the udp */
eloop_event_delete(ifp->ctx->eloop, state->udp_fd);
close(state->udp_fd);
state->udp_fd = -1;
}
@ -2200,8 +2204,12 @@ dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp,
iface, dhcp, from, 0);
return;
}
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
iface->name, state->auth.token->secretid);
if (state->auth.token)
syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32,
iface->name, state->auth.token->secretid);
else
syslog(LOG_DEBUG, "%s: accepted reconfigure key",
iface->name);
} else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
log_dhcp1(LOG_ERR, "no authentication", iface, dhcp, from, 0);
return;
@ -2614,7 +2622,7 @@ dhcp_handleudp(void *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));
(void)read(ctx->udp_fd, buffer, sizeof(buffer));
}
static void
@ -2629,7 +2637,7 @@ dhcp_handleifudp(void *arg)
/* Just read what's in the UDP fd and discard it as we always read
* from the raw fd */
read(state->udp_fd, buffer, sizeof(buffer));
(void)read(state->udp_fd, buffer, sizeof(buffer));
}
static int
@ -2673,25 +2681,23 @@ dhcp_open(struct interface *ifp)
}
int
dhcp_dump(const char *ifname)
dhcp_dump(struct dhcpcd_ctx *ctx, const char *ifname)
{
struct dhcpcd_ctx ctx;
struct interface *ifp;
struct dhcp_state *state;
int r;
ifp = NULL;
if (ctx->ifaces == NULL) {
ctx->ifaces = malloc(sizeof(*ctx->ifaces));
if (ctx->ifaces == NULL)
return -1;
TAILQ_INIT(ctx->ifaces);
}
state = NULL;
memset(&ctx, 0, sizeof(ctx));
ctx.ifaces = malloc(sizeof(*ctx.ifaces));
if (ctx.ifaces == NULL)
goto eexit;
TAILQ_INIT(ctx.ifaces);
ifp = calloc(1, sizeof(*ifp));
if (ifp == NULL)
goto eexit;
ifp->ctx = &ctx;
TAILQ_INSERT_HEAD(ctx.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;
@ -2701,7 +2707,6 @@ dhcp_dump(const char *ifname)
strlcpy(ifp->name, ifname, sizeof(ifp->name));
snprintf(state->leasefile, sizeof(state->leasefile),
LEASEFILE, ifp->name);
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));
@ -2710,28 +2715,14 @@ dhcp_dump(const char *ifname)
if (state->new == NULL) {
if (errno == ENOENT)
syslog(LOG_ERR, "%s: no lease to dump", ifname);
r = -1;
goto cexit;
return -1;
}
state->reason = "DUMP";
r = script_runreason(ifp, state->reason);
goto cexit;
return script_runreason(ifp, state->reason);
eexit:
syslog(LOG_ERR, "%s: %m", __func__);
r = -1;
cexit:
if (state) {
free(state->new);
free(state);
}
if (ifp) {
free(ifp->options);
free(ifp);
}
free(ctx.ifaces);
return r;
return -1;
}
void

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.8.in,v 1.26 2014/02/25 13:20:23 roy Exp $
.\" $NetBSD: dhcpcd.8.in,v 1.27 2014/03/14 11:31:11 roy Exp $
.\" Copyright (c) 2006-2014 Roy Marples
.\" All rights reserved
.\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd February 25, 2014
.Dd March 7, 2014
.Dt DHCPCD 8
.Os
.Sh NAME
@ -31,7 +31,7 @@
.Nd a DHCP client
.Sh SYNOPSIS
.Nm
.Op Fl 46ABbDdEGgHJKLpqTV
.Op Fl 46ABbDdEGgHJKLMpqTV
.Op Fl C , Fl Fl nohook Ar hook
.Op Fl c , Fl Fl script Ar script
.Op Fl e , Fl Fl env Ar value
@ -327,6 +327,10 @@ By default
.Nm
does not request any lease time and leaves it in the hands of the
DHCP server.
.It Fl M , Fl Fl master
Start
.Nm
in master mode even if only one interface specified on the command line.
.It Fl m , Fl Fl metric Ar metric
Metrics are used to prefer an interface over another one, lowest wins.
.Nm
@ -639,11 +643,11 @@ lease and use the files mtime as when it was issued.
Stores the monotonic counter used in the
.Ar replay
field in Authentication Options.
.It Pa @RUNDIR@dhcpcd.pid
.It Pa @RUNDIR@/dhcpcd.pid
Stores the PID of
.Nm
running on all interfaces.
.It Pa @RUNDIR@dhcpcd\- Ns Ar interface Ns .pid
.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .pid
Stores the PID of
.Nm
running on the

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcpcd.c,v 1.3 2014/03/01 11:04:21 roy Exp $");
__RCSID("$NetBSD: dhcpcd.c,v 1.4 2014/03/14 11:31:11 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -300,9 +300,11 @@ find_interface(struct dhcpcd_ctx *ctx, const char *ifname)
{
struct interface *ifp;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (strcmp(ifp->name, ifname) == 0)
return ifp;
if (ctx != NULL && ctx->ifaces != NULL) {
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (strcmp(ifp->name, ifname) == 0)
return ifp;
}
}
return NULL;
}
@ -522,7 +524,8 @@ handle_carrier(struct dhcpcd_ctx *ctx, int carrier, int flags,
* them as some OS's will remove, mark tentative or
* do nothing. */
ipv6_free_ll_callbacks(ifp);
dhcp_drop(ifp, "NOCARRIER");
dhcp_drop(ifp, "EXPIRE");
script_runreason(ifp, "NOCARRIER");
}
} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
if (ifp->carrier != LINK_UP) {
@ -578,7 +581,8 @@ start_interface(void *arg)
size_t i;
char buf[DUID_LEN * 3];
handle_carrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
if (ifp->carrier == LINK_UNKNOWN)
handle_carrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
if (ifp->carrier == LINK_DOWN) {
syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
return;
@ -852,6 +856,7 @@ struct dhcpcd_siginfo {
pid_t pid;
} dhcpcd_siginfo;
#define sigmsg "received signal %s from PID %d, %s"
static void
handle_signal1(void *arg)
{
@ -866,17 +871,17 @@ handle_signal1(void *arg)
do_release = 0;
switch (si->signo) {
case SIGINT:
syslog(LOG_INFO, "received SIGINT from PID %d, stopping",
(int)si->pid);
syslog(LOG_INFO, sigmsg, "INT", (int)si->pid, "stopping");
break;
case SIGTERM:
syslog(LOG_INFO, "received SIGTERM from PID %d, stopping",
(int)si->pid);
syslog(LOG_INFO, sigmsg, "TERM", (int)si->pid, "stopping");
break;
case SIGALRM:
syslog(LOG_INFO, "received SIGALRM from PID %d, rebinding",
(int)si->pid);
syslog(LOG_INFO, sigmsg, "ALRM", (int)si->pid, "releasing");
do_release = 1;
break;
case SIGHUP:
syslog(LOG_INFO, sigmsg, "HUP", (int)si->pid, "rebinding");
free_globals(ctx);
ifo = read_config(ctx, NULL, NULL, NULL);
add_options(ctx, NULL, ifo, ctx->argc, ctx->argv);
@ -892,20 +897,14 @@ handle_signal1(void *arg)
reconf_reboot(ctx, 1, ctx->argc, ctx->argv,
ctx->argc - ctx->ifc);
return;
case SIGHUP:
syslog(LOG_INFO, "received SIGHUP from PID %d, releasing",
(int)si->pid);
do_release = 1;
break;
case SIGUSR1:
syslog(LOG_INFO, "received SIGUSR from PID %d, reconfiguring",
(int)si->pid);
syslog(LOG_INFO, sigmsg, "USR1", (int)si->pid, "reconfiguring");
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
ipv4_applyaddr(ifp);
}
return;
case SIGPIPE:
syslog(LOG_WARNING, "received SIGPIPE");
syslog(LOG_WARNING, "received signal PIPE");
return;
default:
syslog(LOG_ERR,
@ -921,14 +920,14 @@ handle_signal1(void *arg)
}
static void
handle_signal(__unused int sig, siginfo_t *siginfo, __unused void *context)
handle_signal(int sig, siginfo_t *siginfo, __unused void *context)
{
/* So that we can operate safely under a signal we instruct
* eloop to pass a copy of the siginfo structure to handle_signal1
* as the very first thing to do. */
dhcpcd_siginfo.signo = siginfo->si_signo;
dhcpcd_siginfo.pid = siginfo->si_pid;
dhcpcd_siginfo.signo = sig;
dhcpcd_siginfo.pid = siginfo ? siginfo->si_pid : 0;
eloop_timeout_add_now(dhcpcd_ctx->eloop,
handle_signal1, &dhcpcd_siginfo);
}
@ -1118,6 +1117,7 @@ main(int argc, char **argv)
#endif
#ifdef USE_SIGNALS
int sig;
const char *siga;
#endif
struct timespec ts;
@ -1125,6 +1125,7 @@ main(int argc, char **argv)
#ifdef USE_SIGNALS
dhcpcd_ctx = &ctx;
sig = 0;
siga = NULL;
#endif
closefrom(3);
openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
@ -1166,15 +1167,19 @@ main(int argc, char **argv)
#ifdef USE_SIGNALS
case 'g':
sig = SIGUSR1;
siga = "USR1";
break;
case 'k':
sig = SIGHUP;
sig = SIGALRM;
siga = "ARLM";
break;
case 'n':
sig = SIGALRM;
sig = SIGHUP;
siga = "HUP";
break;
case 'x':
sig = SIGTERM;
siga = "TERM";;
break;
#endif
case 'T':
@ -1194,6 +1199,9 @@ main(int argc, char **argv)
ctx.argv = argv;
ctx.argc = argc;
ctx.ifc = argc - optind;
ctx.ifv = argv + optind;
ifo = read_config(&ctx, NULL, NULL, NULL);
opt = add_options(&ctx, NULL, ifo, argc, argv);
if (opt != 1) {
@ -1247,7 +1255,7 @@ main(int argc, char **argv)
if (!(ctx.options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
/* If we have any other args, we should run as a single dhcpcd
* instance for that interface. */
if (optind == argc - 1) {
if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) {
if (strlen(argv[optind]) > IF_NAMESIZE) {
syslog(LOG_ERR, "%s: interface name too long",
argv[optind]);
@ -1270,13 +1278,15 @@ main(int argc, char **argv)
syslog(LOG_ERR, "dumplease requires an interface");
goto exit_failure;
}
if (dhcp_dump(argv[optind]) == -1)
if (dhcp_dump(&ctx, argv[optind]) == -1)
goto exit_failure;
goto exit_success;
}
#ifdef USE_SIGNALS
if (!(ctx.options & (DHCPCD_MASTER | DHCPCD_TEST))) {
if (!(ctx.options & DHCPCD_TEST) &&
(sig == 0 || ctx.ifc != 0))
{
#endif
if (ctx.options & DHCPCD_MASTER)
i = -1;
@ -1318,20 +1328,20 @@ main(int argc, char **argv)
if (sig != 0) {
pid = read_pid(pidfile);
if (pid != 0)
syslog(LOG_INFO, "sending signal %d to pid %d",
sig, pid);
syslog(LOG_INFO, "sending signal %s to pid %d",
siga, pid);
if (pid == 0 || kill(pid, sig) != 0) {
if (sig != SIGALRM && errno != EPERM)
if (sig != SIGHUP && errno != EPERM)
syslog(LOG_ERR, ""PACKAGE" not running");
if (pid != 0 && errno != ESRCH) {
syslog(LOG_ERR, "kill: %m");
goto exit_failure;
}
unlink(pidfile);
if (sig != SIGALRM)
if (sig != SIGHUP)
goto exit_failure;
} else {
if (sig == SIGALRM || sig == SIGUSR1)
if (sig == SIGHUP || sig == SIGUSR1)
goto exit_success;
/* Spin until it exits */
syslog(LOG_INFO, "waiting for pid %d to exit", pid);
@ -1405,8 +1415,10 @@ main(int argc, char **argv)
}
#endif
ctx.ifc = argc - optind;
ctx.ifv = argv + optind;
#ifdef __FreeBSD__
syslog(LOG_WARNING, "FreeBSD errors that are worked around:");
syslog(LOG_WARNING, "IPv4 subnet routes cannot be deleted");
#endif
/* When running dhcpcd against a single interface, we need to retain
* the old behaviour of waiting for an IP address */

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if-bsd.c,v 1.4 2014/02/25 13:20:23 roy Exp $");
__RCSID("$NetBSD: if-bsd.c,v 1.5 2014/03/14 11:31:11 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -50,6 +50,7 @@
#elif __APPLE__
/* FIXME: Add apple includes so we can work out SSID */
#else
# include <net80211/ieee80211.h>
# include <net80211/ieee80211_ioctl.h>
#endif
@ -285,19 +286,24 @@ if_route(const struct rt *rt, int action)
memset(&rtm, 0, sizeof(rtm));
rtm.hdr.rtm_version = RTM_VERSION;
rtm.hdr.rtm_seq = 1;
rtm.hdr.rtm_addrs = RTA_DST;
if (action == 0)
rtm.hdr.rtm_type = RTM_CHANGE;
else if (action > 0)
else if (action > 0) {
rtm.hdr.rtm_type = RTM_ADD;
else
rtm.hdr.rtm_addrs |= RTA_GATEWAY;
} else
rtm.hdr.rtm_type = RTM_DELETE;
rtm.hdr.rtm_flags = RTF_UP;
#ifdef SIOCGIFPRIORITY
rtm.hdr.rtm_priority = rt->metric;
#endif
/* None interface subnet routes are static. */
if (rt->gate.s_addr != INADDR_ANY ||
rt->net.s_addr != state->net.s_addr ||
rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr))
rtm.hdr.rtm_flags |= RTF_STATIC;
rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
if (rt->dest.s_addr == rt->gate.s_addr &&
rt->net.s_addr == INADDR_BROADCAST)
rtm.hdr.rtm_flags |= RTF_HOST;
@ -313,17 +319,19 @@ if_route(const struct rt *rt, int action)
}
ADDADDR(&rt->dest);
if ((rtm.hdr.rtm_flags & RTF_HOST &&
rt->gate.s_addr != htonl(INADDR_LOOPBACK)) ||
!(rtm.hdr.rtm_flags & RTF_STATIC))
{
/* Make us a link layer socket for the host gateway */
memset(&su, 0, sizeof(su));
su.sdl.sdl_len = sizeof(struct sockaddr_dl);
link_addr(rt->iface->name, &su.sdl);
ADDSU;
} else
ADDADDR(&rt->gate);
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
if ((rtm.hdr.rtm_flags & RTF_HOST &&
rt->gate.s_addr != htonl(INADDR_LOOPBACK)) ||
!(rtm.hdr.rtm_flags & RTF_STATIC))
{
/* Make us a link layer socket for the host gateway */
memset(&su, 0, sizeof(su));
su.sdl.sdl_len = sizeof(struct sockaddr_dl);
link_addr(rt->iface->name, &su.sdl);
ADDSU;
} else
ADDADDR(&rt->gate);
}
if (rtm.hdr.rtm_addrs & RTA_NETMASK)
ADDADDR(&rt->net);
@ -411,7 +419,7 @@ if_route6(const struct rt6 *rt, int action)
char *bp = rtm.buffer;
size_t l;
int s, retval;
const struct ipv6_addr_l *lla;
const struct ipv6_addr *lla;
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
return -1;
@ -456,8 +464,11 @@ if_route6(const struct rt6 *rt, int action)
rtm.hdr.rtm_type = RTM_ADD;
else
rtm.hdr.rtm_type = RTM_DELETE;
rtm.hdr.rtm_flags = RTF_UP;
rtm.hdr.rtm_addrs = RTA_DST | RTA_NETMASK;
#ifdef SIOCGIFPRIORITY
rtm.hdr.rtm_priority = rt->metric;
#endif
/* None interface subnet routes are static. */
if (IN6_IS_ADDR_UNSPECIFIED(&rt->dest) &&
IN6_IS_ADDR_UNSPECIFIED(&rt->net))
@ -467,19 +478,21 @@ if_route6(const struct rt6 *rt, int action)
rtm.hdr.rtm_flags |= RTF_CLONING;
#endif
rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
if (action >= 0)
rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
rtm.hdr.rtm_addrs |= RTA_GATEWAY | RTA_IFP | RTA_IFA;
ADDADDR(&rt->dest);
if (!(rtm.hdr.rtm_flags & RTF_GATEWAY)) {
lla = ipv6_linklocal(rt->iface);
if (lla == NULL) /* unlikely as we need a LL to get here */
return -1;
ADDADDRS(&lla->addr, rt->iface->index);
} else {
lla = NULL;
ADDADDRS(&rt->gate, rt->iface->index);
lla = NULL;
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
if (!(rtm.hdr.rtm_flags & RTF_GATEWAY)) {
lla = ipv6_linklocal(rt->iface);
if (lla == NULL) /* unlikely */
return -1;
ADDADDRS(&lla->addr, rt->iface->index);
} else {
lla = NULL;
ADDADDRS(&rt->gate, rt->iface->index);
}
}
if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
@ -582,7 +595,7 @@ manage_link(struct dhcpcd_ctx *ctx)
#ifdef INET
struct rt rt;
#endif
#if defined(INET6) && !defined(LISTEN_DAD)
#ifdef INET6
struct in6_addr ia6;
struct sockaddr_in6 *sin6;
int ifa_flags;
@ -701,7 +714,7 @@ manage_link(struct dhcpcd_ctx *ctx)
&rt.dest, &rt.net, &rt.gate);
break;
#endif
#if defined(INET6) && !defined(LISTEN_DAD)
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6*)(void *)
rti_info[RTAX_IFA];

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if-options.c,v 1.7 2014/03/01 11:04:21 roy Exp $");
__RCSID("$NetBSD: if-options.c,v 1.8 2014/03/14 11:31:11 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -127,6 +127,7 @@ const struct option cf_options[] = {
{"broadcast", no_argument, NULL, 'J'},
{"nolink", no_argument, NULL, 'K'},
{"noipv4ll", no_argument, NULL, 'L'},
{"master", no_argument, NULL, 'M'},
{"nooption", optional_argument, NULL, 'O'},
{"require", required_argument, NULL, 'Q'},
{"static", required_argument, NULL, 'S'},
@ -929,6 +930,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
case 'L':
ifo->options &= ~DHCPCD_IPV4LL;
break;
case 'M':
ifo->options |= DHCPCD_MASTER;
break;
case 'O':
arg = set_option_space(ctx, arg, &d, &dl, ifo,
&request, &require, &no);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6nd.c,v 1.6 2014/03/01 11:04:21 roy Exp $");
__RCSID("$NetBSD: ipv6nd.c,v 1.7 2014/03/14 11:31:11 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -49,14 +49,6 @@
#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"
@ -66,11 +58,6 @@
#include "ipv6nd.h"
#include "script.h"
#if defined(LISTEN_DAD) && defined(INET6)
# warning kernel does not report DAD results to userland
# warning listening to duplicated addresses on the wire
#endif
/* Debugging Router Solicitations is a lot of spam, so disable it */
//#define DEBUG_RS
@ -172,16 +159,10 @@ ipv6nd_open(struct dhcpcd_ctx *dctx)
struct ipv6_ctx *ctx;
int on;
struct icmp6_filter filt;
#ifdef IPV6_SEND_DAD
union {
struct sockaddr sa;
struct sockaddr_in6 sin;
} su;
#endif
ctx = dctx->ipv6;
if (ctx->nd_fd != -1)
goto unspec;
return ctx->nd_fd;
#ifdef SOCK_CLOEXEC
ctx->nd_fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
IPPROTO_ICMPV6);
@ -206,6 +187,12 @@ ipv6nd_open(struct dhcpcd_ctx *dctx)
}
#endif
/* RFC4861 4.1 */
on = 255;
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&on, sizeof(on)) == -1)
goto eexit;
on = 1;
if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&on, sizeof(on)) == -1)
@ -224,62 +211,6 @@ ipv6nd_open(struct dhcpcd_ctx *dctx)
goto eexit;
eloop_event_add(dctx->eloop, ctx->nd_fd, ipv6nd_handledata, dctx);
unspec:
#ifdef IPV6_SEND_DAD
if (ctx->unspec_fd != -1)
return ctx->nd_fd;
ICMP6_FILTER_SETBLOCKALL(&filt);
/* We send DAD requests from the unspecified address. */
#ifdef SOCK_CLOEXEC
ctx->unspec_fd = socket(AF_INET6,
SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
IPPROTO_ICMPV6);
if (ctx->unspec_fd == -1)
return -1;
#else
if ((ctx->unspec_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
return -1;
if ((on = fcntl(ctx->unspec_fd, F_GETFD, 0)) == -1 ||
fcntl(ctx->unspec_fd, F_SETFD, on | FD_CLOEXEC) == -1)
{
close(ctx->unspec_fd);
ctx->unspec_fd = -1;
return -1;
}
if ((on = fcntl(ctx->unspec_fd, F_GETFL, 0)) == -1 ||
fcntl(ctx->unspec_fd, F_SETFL, on | O_NONBLOCK) == -1)
{
close(ctx->unspec_fd);
ctx->unspec_fd = -1;
return -1;
}
#endif
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(ctx->unspec_fd, &su.sa, sizeof(su.sin)) == -1)
goto eexit;
#endif
#ifdef LISTEN_DAD
if (!ctx->dad_warned) {
syslog(LOG_WARNING,
"kernel does not report DAD results to userland");
syslog(LOG_WARNING,
"warning listening to duplicated addresses on the wire");
ctx->dad_warned = 1;
}
#endif
return ctx->nd_fd;
eexit:
@ -288,12 +219,6 @@ eexit:
close(ctx->nd_fd);
ctx->nd_fd = -1;
}
#ifdef IPV6_SEND_DAD
if (ctx->unpsec_fd != -1) {
close(ctx->unspec_fd);
ctx->unspec_fd = -1;
}
#endif
return -1;
}
@ -331,7 +256,6 @@ ipv6nd_sendrsprobe(void *arg)
struct sockaddr_in6 dst;
struct cmsghdr *cm;
struct in6_pktinfo pi;
int hoplimit = HOPLIMIT;
if (ipv6_linklocal(ifp) == NULL) {
syslog(LOG_DEBUG,
@ -369,15 +293,6 @@ ipv6nd_sendrsprobe(void *arg)
pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
/* Hop limit */
cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
if (cm == NULL) /* unlikely */
return;
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(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
@ -581,16 +496,11 @@ ipv6nd_dadcallback(void *arg)
int wascompleted, found;
wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
ipv6nd_cancelprobeaddr(ap);
ap->flags |= IPV6_AF_DADCOMPLETED;
if (ap->flags & IPV6_AF_DUPLICATED)
/* No idea what how to try and make another address :( */
syslog(LOG_WARNING, "%s: DAD detected %s",
ap->iface->name, ap->saddr);
#ifdef IPV6_SEND_DAD
else
ipv6_addaddr(ap);
#endif
if (!wascompleted) {
ifp = ap->iface;
@ -611,7 +521,7 @@ ipv6nd_dadcallback(void *arg)
found = 1;
}
if (wascompleted && found && rap->lifetime) {
if (wascompleted && found) {
syslog(LOG_DEBUG,
"%s: Router Advertisement DAD completed",
rap->iface->name);
@ -687,11 +597,6 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
}
nd_ra = (struct nd_router_advert *)icp;
/* Don't bother doing anything if we don't know about a router
* expiring */
if ((rap == NULL || rap->lifetime == 0)
&& nd_ra->nd_ra_router_lifetime == 0)
return;
/* We don't want to spam the log with the fact we got an RA every
* 30 seconds or so, so only spam the log if it's different. */
@ -860,13 +765,13 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
ntohl(pi->nd_opt_pi_preferred_time);
ap->nsprobes = 0;
if (opt) {
l = strlen(opt);
tmp = realloc(opt,
l + strlen(ap->saddr) + 2);
l = strlen(opt) + 1;
m = strlen(ap->saddr) + 1;
tmp = realloc(opt, l + m);
if (tmp) {
opt = tmp;
opt[l] = ' ';
strcpy(opt + l + 1, ap->saddr);
opt[l - 1] = ' ';
strlcpy(opt + l, ap->saddr, m);
}
} else
opt = strdup(ap->saddr);
@ -1001,14 +906,10 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
script_runreason(ifp, "TEST");
goto handle_flag;
}
ipv6nd_probeaddrs(&rap->addrs);
ipv6_addaddrs(&rap->addrs);
ipv6_buildroutes(ifp->ctx);
/* We will get run by the expire function */
if (rap->lifetime) {
if (ipv6nd_scriptrun(rap))
return;
}
if (ipv6nd_scriptrun(rap))
return;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
@ -1025,15 +926,13 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
handle_flag:
if (rap->flags & ND_RA_FLAG_MANAGED) {
if (rap->lifetime && new_data &&
dhcp6_start(ifp, DH6S_INIT) == -1)
if (new_data && dhcp6_start(ifp, DH6S_INIT) == -1)
syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
} else if (rap->flags & ND_RA_FLAG_OTHER) {
if (rap->lifetime && new_data &&
dhcp6_start(ifp, DH6S_INFORM) == -1)
if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
} else {
if (rap->lifetime && new_data)
if (new_data)
syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
ifp->name);
if (ifp->ctx->options & DHCPCD_TEST) {
@ -1132,24 +1031,25 @@ ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
if (new) {
**var = new;
new = strchr(**var, '=');
if (new)
strcpy(new + 1,
rao->option);
else
if (new) {
len -= (new - **var);
strlcpy(new + 1,
rao->option,
len - 1);
} else
syslog(LOG_ERR,
"new is null");
}
continue;
}
new = realloc(**var,
strlen(**var) + 1 +
strlen(rao->option) + 1);
len = strlen(rao->option) + 1;
new = realloc(**var, strlen(**var) + 1 + len);
if (new == NULL)
return -1;
**var = new;
new += strlen(new);
*new++ = ' ';
strcpy(new, rao->option);
strlcpy(new, rao->option, len);
continue;
}
if (env) {
@ -1202,26 +1102,29 @@ ipv6nd_expirera(void *arg)
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
if (rap->iface != ifp)
continue;
lt.tv_sec = rap->lifetime;
lt.tv_usec = 0;
timeradd(&rap->received, &lt, &expire);
if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
valid = 0;
if (!rap->expired) {
syslog(LOG_WARNING,
"%s: %s: router expired",
ifp->name, rap->sfrom);
rap->expired = expired = 1;
ipv6nd_cancelproberouter(rap);
valid = 0;
if (rap->lifetime) {
lt.tv_sec = rap->lifetime;
lt.tv_usec = 0;
timeradd(&rap->received, &lt, &expire);
if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
if (!rap->expired) {
syslog(LOG_WARNING,
"%s: %s: router expired",
ifp->name, rap->sfrom);
rap->expired = expired = 1;
ipv6nd_cancelproberouter(rap);
}
} else {
valid = 1;
timersub(&expire, &now, &lt);
if (!timerisset(&next) ||
timercmp(&next, &lt, >))
next = lt;
}
} else {
valid = 1;
timersub(&expire, &now, &lt);
if (!timerisset(&next) || timercmp(&next, &lt, >))
next = lt;
}
/* Addresses are expired in ipv6ns_probeaddrs
/* Addresses are expired in ipv6_addaddrs
* so that DHCPv6 addresses can be removed also. */
TAILQ_FOREACH_SAFE(rao, &rap->options, next, raon) {
if (rap->expired) {
@ -1332,201 +1235,6 @@ ipv6nd_unreachable(void *arg)
&tv, ipv6nd_proberouter, rap);
}
#ifdef LISTEN_DAD
void
ipv6nd_cancelprobeaddr(struct ipv6_addr *ap)
{
eloop_timeout_delete(ap->iface->ctx->eloop, ipv6nd_probeaddr, ap);
if (ap->dadcallback)
eloop_timeout_delete(ap->iface->ctx->eloop, ap->dadcallback,ap);
}
#endif
void
ipv6nd_probeaddr(void *arg)
{
struct ipv6_addr *ap = arg;
#ifdef IPV6_SEND_DAD
struct nd_neighbor_solicit *ns;
struct nd_opt_hdr *nd;
struct sockaddr_in6 dst;
struct cmsghdr *cm;
struct in6_pktinfo pi;
int hoplimit = HOPLIMIT;
#else
#ifdef LISTEN_DAD
struct timeval tv, rtv;
struct timeval mtv;
int i;
#endif
#endif
if (ap->dadcallback &&
((ap->flags & IPV6_AF_NEW) == 0 ||
ap->nsprobes >= ap->iface->options->dadtransmits))
{
#ifdef IPV6_SEND_DAD
ap->dadcallback(ap);
#else
if (!(ap->flags & IPV6_AF_AUTOCONF) ||
ap->iface->options->options & DHCPCD_IPV6RA_OWN)
ipv6_addaddr(ap);
#endif
return;
}
if (ipv6nd_open(ap->iface->ctx) == -1) {
syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
return;
}
ap->flags &= ~IPV6_AF_DADCOMPLETED;
#ifdef IPV6_SEND_DAD
if (!ap->ns) {
ap->nslen = sizeof(*ns) + ROUNDUP8(ap->iface->hwlen + 2);
ap->ns = calloc(1, ap->nslen);
if (ap->ns == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
return;
}
ns = (struct nd_neighbor_solicit *)(void *)ap->ns;
ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
//ns->nd_ns_cksum = 0;
//ns->nd_ns_code = 0;
//ns->nd_ns_reserved = 0;
ns->nd_ns_target = ap->addr;
nd = (struct nd_opt_hdr *)(ap->ns + sizeof(*ns));
nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
nd->nd_opt_len = (ROUNDUP8(ap->iface->hwlen + 2)) >> 3;
memcpy(nd + 1, ap->iface->hwaddr, ap->iface->hwlen);
}
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN
dst.sin6_len = sizeof(dst);
#endif
dst.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
dst.sin6_addr.s6_addr16[1] = 0;
dst.sin6_addr.s6_addr32[1] = 0;
dst.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
dst.sin6_addr.s6_addr32[3] = ap->addr.s6_addr32[3];
dst.sin6_addr.s6_addr[12] = 0xff;
//memcpy(&dst.sin6_addr, &ap->addr, sizeof(dst.sin6_addr));
dst.sin6_scope_id = ap->iface->index;
ctx = ap->iface->ctx->ipv6;
ctx->sndhdr.msg_name = (caddr_t)&dst;
ctx->sndhdr.msg_iov[0].iov_base = ap->ns;
ctx->sndhdr.msg_iov[0].iov_len = ap->nslen;
/* Set the outbound interface */
cm = CMSG_FIRSTHDR(&ctx->sndhdr);
if (cm == NULL) /* unlikely */
return;
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = ap->iface->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
/* Hop limit */
cm = CMSG_NXTHDR(&sndhdr, cm);
if (cm == NULL) /* unlikely */
return;
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_HOPLIMIT;
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
#ifdef DEBUG_NS
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
ap->iface->name, ap->saddr);
if (ap->dadcallback == NULL)
syslog(LOG_WARNING, "%s: no callback!", ap->iface->name);
#endif
if (sendmsg(unspec_sock, &sndhdr, 0) == -1) {
syslog(LOG_ERR, "%s: %s: sendmsg: %m",
ap->iface->name, __func__);
return;
}
if (ap->dadcallback) {
ms_to_tv(&tv, RETRANS_TIMER);
ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
rtv.tv_sec = 0;
rtv.tv_usec = arc4random() %
(MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
timeradd(&tv, &rtv, &tv);
eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv,
++(ap->nsprobes) < ap->iface->options->dadtransmits ?
ipv6nd_probeaddr : ap->dadcallback,
ap);
}
#else /* IPV6_SEND_DAD */
if (!(ap->flags & IPV6_AF_AUTOCONF) ||
ap->iface->options->options & DHCPCD_IPV6RA_OWN)
ipv6_addaddr(ap);
#ifdef LISTEN_DAD
/* Let the kernel handle DAD.
* We don't know the timings, so just wait for the max */
if (ap->dadcallback) {
mtv.tv_sec = 0;
mtv.tv_usec = 0;
for (i = 0; i < ap->iface->options->dadtransmits; i++) {
ms_to_tv(&tv, RETRANS_TIMER);
ms_to_tv(&rtv, MAX_RANDOM_FACTOR);
timeradd(&tv, &rtv, &tv);
timeradd(&mtv, &tv, &mtv);
}
eloop_timeout_add_tv(ap->iface->ctx->eloop,
&mtv, ap->dadcallback, ap);
}
#endif
#endif /* IPV6_SEND_DAD */
}
ssize_t
ipv6nd_probeaddrs(struct ipv6_addrhead *addrs)
{
struct ipv6_addr *ap, *apn;
ssize_t i;
i = 0;
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
if (ap->prefix_vltime == 0) {
TAILQ_REMOVE(addrs, ap, next);
if (ap->flags & IPV6_AF_ADDED) {
syslog(LOG_INFO, "%s: deleting address %s",
ap->iface->name, ap->saddr);
i++;
if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
del_address6(ap) == -1 &&
errno != EADDRNOTAVAIL && errno != ENXIO)
syslog(LOG_ERR, "del_address6 %m");
}
if (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);
if (ap->flags & IPV6_AF_NEW)
i++;
}
}
return i;
}
void
ipv6nd_proberouter(void *arg)
{
@ -1536,7 +1244,6 @@ ipv6nd_proberouter(void *arg)
struct sockaddr_in6 dst;
struct cmsghdr *cm;
struct in6_pktinfo pi;
int hoplimit = HOPLIMIT;
struct timeval tv, rtv;
struct ipv6_ctx *ctx;
@ -1588,15 +1295,6 @@ ipv6nd_proberouter(void *arg)
pi.ipi6_ifindex = rap->iface->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
/* Hop limit */
cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
if (cm == NULL) /* unlikely */
return;
cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_HOPLIMIT;
cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
#ifdef DEBUG_NS
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
rap->iface->name, rap->sfrom);
@ -1636,16 +1334,8 @@ ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
struct nd_neighbor_advert *nd_na;
struct ra *rap;
int is_router, is_solicited;
#ifdef DEBUG_NS
int found;
#endif
struct timeval tv;
#ifdef LISTEN_DAD
struct dhcp6_state *d6state;
struct ipv6_addr *ap;
#endif
if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
syslog(LOG_ERR, "IPv6 NA packet too short from %s", ctx->sfrom);
return;
@ -1669,55 +1359,16 @@ ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
return;
}
#ifdef DEBUG_NS
found = 0;
#endif
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,
if (rap->iface == ifp &&
memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
sizeof(rap->from.s6_addr)) == 0)
break;
#ifdef LISTEN_DAD
TAILQ_FOREACH(ap, &rap->addrs, next) {
if (memcmp(ap->addr.s6_addr,
nd_na->nd_na_target.s6_addr,
sizeof(ap->addr.s6_addr)) == 0)
{
ap->flags |= IPV6_AF_DUPLICATED;
if (ap->dadcallback)
ap->dadcallback(ap);
#ifdef DEBUG_NS
found++;
#endif
}
}
#endif
}
if (rap == NULL) {
#ifdef LISTEN_DAD
d6state = D6_STATE(ifp);
if (d6state) {
TAILQ_FOREACH(ap, &d6state->addrs, next) {
if (memcmp(ap->addr.s6_addr,
nd_na->nd_na_target.s6_addr,
sizeof(ap->addr.s6_addr)) == 0)
{
ap->flags |= IPV6_AF_DUPLICATED;
if (ap->dadcallback)
ap->dadcallback(ap);
#ifdef DEBUG_NS
found++;
#endif
}
}
}
#endif
#ifdef DEBUG_NS
if (found == 0)
syslog(LOG_DEBUG, "%s: unexpected NA from %s",
ifp->name, ctx->sfrom);
syslog(LOG_DEBUG, "%s: unexpected NA from s",
ifp->name, ctx->sfrom);
#endif
return;
}
@ -1774,6 +1425,8 @@ ipv6nd_handledata(void *arg)
dhcpcd_ctx = arg;
ctx = dhcpcd_ctx->ipv6;
ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE(sizeof(int));
len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
if (len == -1) {
syslog(LOG_ERR, "recvmsg: %m");

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: net.c,v 1.5 2014/02/25 13:20:23 roy Exp $");
__RCSID("$NetBSD: net.c,v 1.6 2014/03/14 11:31:11 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -253,13 +253,26 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
#endif
#ifdef AF_LINK
const struct sockaddr_dl *sdl;
#ifdef SIOCGIFPRIORITY
struct ifreq ifr;
int s_inet;
#endif
#ifdef IFLR_ACTIVE
struct if_laddrreq iflr;
int socket_aflink;
int s_link;
#endif
socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
if (socket_aflink == -1)
#ifdef SIOCGIFPRIORITY
if ((s_inet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return NULL;
#endif
#ifdef IFLR_ACTIVE
if ((s_link = socket(AF_LINK, SOCK_DGRAM, 0)) == -1) {
#ifdef SIOCGIFPRIORITY
close(s_inet);
#endif
return NULL;
}
memset(&iflr, 0, sizeof(iflr));
#endif
#elif AF_PACKET
@ -268,7 +281,6 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
if (getifaddrs(&ifaddrs) == -1)
return NULL;
ifs = malloc(sizeof(*ifs));
if (ifs == NULL)
return NULL;
@ -342,8 +354,10 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
}
ifp = calloc(1, sizeof(*ifp));
if (ifp == NULL)
return NULL;
if (ifp == NULL) {
syslog(LOG_ERR, "%s: %m", __func__);
break;
}
ifp->ctx = ctx;
strlcpy(ifp->name, p, sizeof(ifp->name));
ifp->flags = ifa->ifa_flags;
@ -381,7 +395,7 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
iflr.flags = IFLR_PREFIX;
iflr.prefixlen = sdl->sdl_alen * NBBY;
if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
if (ioctl(s_link, SIOCGLIFADDR, &iflr) == -1 ||
!(iflr.flags & IFLR_ACTIVE))
{
free_interface(ifp);
@ -466,6 +480,13 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
continue;
}
#ifdef SIOCGIFPRIORITY
/* Respect the interface priority */
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(s_inet, SIOCGIFPRIORITY, &ifr) == 0)
ifp->metric = ifr.ifr_metric;
#else
/* We reserve the 100 range for virtual interfaces, if and when
* we can work them out. */
ifp->metric = 200 + ifp->index;
@ -473,6 +494,7 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
ifp->wireless = 1;
ifp->metric += 100;
}
#endif
TAILQ_INSERT_TAIL(ifs, ifp, next);
}
@ -515,8 +537,11 @@ discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
freeifaddrs(ifaddrs);
#ifdef SIOCGIFPRIORITY
close(s_inet);
#endif
#ifdef IFLR_ACTIVE
close(socket_aflink);
close(s_link);
#endif
return ifs;