xref: /minix/external/bsd/dhcpcd/dist/if.c (revision 9f20bfa6)
1 #include <sys/cdefs.h>
2  __RCSID("$NetBSD: if.c,v 1.16 2015/09/04 12:25:01 roy Exp $");
3 
4 /*
5  * dhcpcd - DHCP client daemon
6  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7  * All rights reserved
8 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 
36 #include <net/if.h>
37 #include <net/if_arp.h>
38 #include <netinet/in.h>
39 #ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
40 #  include <net/if_var.h>
41 #endif
42 #ifdef AF_LINK
43 #  include <net/if_dl.h>
44 #  include <net/if_types.h>
45 #  include <netinet/in_var.h>
46 #endif
47 #ifdef AF_PACKET
48 #  include <netpacket/packet.h>
49 #endif
50 #ifdef SIOCGIFMEDIA
51 #  include <net/if_media.h>
52 #endif
53 #include <net/route.h>
54 
55 #include <ctype.h>
56 #include <errno.h>
57 #include <ifaddrs.h>
58 #include <fnmatch.h>
59 #include <stddef.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <fcntl.h>
65 
66 #include "config.h"
67 #include "common.h"
68 #include "dev.h"
69 #include "dhcp.h"
70 #include "dhcp6.h"
71 #include "if.h"
72 #include "if-options.h"
73 #include "ipv4.h"
74 #include "ipv4ll.h"
75 #include "ipv6nd.h"
76 
77 void
if_free(struct interface * ifp)78 if_free(struct interface *ifp)
79 {
80 
81 	if (ifp == NULL)
82 		return;
83 	ipv4ll_free(ifp);
84 	dhcp_free(ifp);
85 	ipv4_free(ifp);
86 	dhcp6_free(ifp);
87 	ipv6nd_free(ifp);
88 	ipv6_free(ifp);
89 	free_options(ifp->options);
90 	free(ifp);
91 }
92 
93 int
if_opensockets(struct dhcpcd_ctx * ctx)94 if_opensockets(struct dhcpcd_ctx *ctx)
95 {
96 
97 	if ((ctx->link_fd = if_openlinksocket()) == -1)
98 		return -1;
99 
100 	ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM, 0, O_CLOEXEC);
101 	if (ctx->pf_inet_fd == -1)
102 		return -1;
103 
104 #if defined(INET6) && defined(BSD)
105 	ctx->pf_inet6_fd = xsocket(PF_INET6, SOCK_DGRAM, 0, O_CLOEXEC);
106 	if (ctx->pf_inet6_fd == -1)
107 		return -1;
108 #endif
109 
110 #ifdef IFLR_ACTIVE
111 	ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0, O_CLOEXEC);
112 	if (ctx->pf_link_fd == -1)
113 		return -1;
114 #endif
115 
116 	return 0;
117 }
118 
119 int
if_carrier(struct interface * ifp)120 if_carrier(struct interface *ifp)
121 {
122 	int r;
123 	struct ifreq ifr;
124 #ifdef SIOCGIFMEDIA
125 	struct ifmediareq ifmr;
126 #endif
127 
128 	memset(&ifr, 0, sizeof(ifr));
129 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
130 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
131 		return LINK_UNKNOWN;
132 	ifp->flags = (unsigned int)ifr.ifr_flags;
133 
134 #ifdef SIOCGIFMEDIA
135 	memset(&ifmr, 0, sizeof(ifmr));
136 	strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
137 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) != -1 &&
138 	    ifmr.ifm_status & IFM_AVALID)
139 		r = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN;
140 	else
141 		r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN;
142 #else
143 	r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
144 #endif
145 	return r;
146 }
147 
148 int
if_setflag(struct interface * ifp,short flag)149 if_setflag(struct interface *ifp, short flag)
150 {
151 	struct ifreq ifr;
152 	int r;
153 
154 	memset(&ifr, 0, sizeof(ifr));
155 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
156 	r = -1;
157 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == 0) {
158 		if (flag == 0 || (ifr.ifr_flags & flag) == flag)
159 			r = 0;
160 		else {
161 			ifr.ifr_flags |= flag;
162 			if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) ==0)
163 				r = 0;
164 		}
165 		ifp->flags = (unsigned int)ifr.ifr_flags;
166 	}
167 	return r;
168 }
169 
170 static int
if_hasconf(struct dhcpcd_ctx * ctx,const char * ifname)171 if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
172 {
173 	int i;
174 
175 	for (i = 0; i < ctx->ifcc; i++) {
176 		if (strcmp(ctx->ifcv[i], ifname) == 0)
177 			return 1;
178 	}
179 	return 0;
180 }
181 
if_learnaddrs1(struct dhcpcd_ctx * ctx,struct if_head * ifs,struct ifaddrs * ifaddrs)182 static void if_learnaddrs1(struct dhcpcd_ctx *ctx, struct if_head *ifs,
183     struct ifaddrs *ifaddrs)
184 {
185 	struct ifaddrs *ifa;
186 	struct interface *ifp;
187 #ifdef INET
188 	const struct sockaddr_in *addr, *net, *dst;
189 #endif
190 #ifdef INET6
191 	struct sockaddr_in6 *sin6, *net6;
192 #endif
193 	int ifa_flags;
194 
195 
196 	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
197 		if (ifa->ifa_addr == NULL)
198 			continue;
199 		if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
200 			continue;
201 		switch(ifa->ifa_addr->sa_family) {
202 #ifdef INET
203 		case AF_INET:
204 			addr = (const struct sockaddr_in *)
205 			    (void *)ifa->ifa_addr;
206 			net = (const struct sockaddr_in *)
207 			    (void *)ifa->ifa_netmask;
208 			if (ifa->ifa_flags & IFF_POINTOPOINT)
209 				dst = (const struct sockaddr_in *)
210 				    (void *)ifa->ifa_dstaddr;
211 			else
212 				dst = NULL;
213 			ifa_flags = if_addrflags(&addr->sin_addr, ifp);
214 			ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
215 				&addr->sin_addr,
216 				&net->sin_addr,
217 				dst ? &dst->sin_addr : NULL, ifa_flags);
218 			break;
219 #endif
220 #ifdef INET6
221 		case AF_INET6:
222 			sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
223 			net6 = (struct sockaddr_in6 *)(void *)ifa->ifa_netmask;
224 #ifdef __KAME__
225 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
226 				/* Remove the scope from the address */
227 				sin6->sin6_addr.s6_addr[2] =
228 				    sin6->sin6_addr.s6_addr[3] = '\0';
229 #endif
230 			ifa_flags = if_addrflags6(&sin6->sin6_addr, ifp);
231 			if (ifa_flags != -1)
232 				ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
233 				    ifa->ifa_name,
234 				    &sin6->sin6_addr,
235 				    ipv6_prefixlen(&net6->sin6_addr),
236 				    ifa_flags);
237 			break;
238 #endif
239 		}
240 	}
241 }
242 
243 struct if_head *
if_discover(struct dhcpcd_ctx * ctx,int argc,char * const * argv)244 if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
245 {
246 	struct ifaddrs *ifaddrs, *ifa;
247 	char *p;
248 	int i;
249 	struct if_head *ifs;
250 	struct interface *ifp;
251 #ifdef __linux__
252 	char ifn[IF_NAMESIZE];
253 #endif
254 #ifdef AF_LINK
255 	const struct sockaddr_dl *sdl;
256 #ifdef SIOCGIFPRIORITY
257 	struct ifreq ifr;
258 #endif
259 #ifdef IFLR_ACTIVE
260 	struct if_laddrreq iflr;
261 #endif
262 
263 #ifdef IFLR_ACTIVE
264 	memset(&iflr, 0, sizeof(iflr));
265 #endif
266 #elif AF_PACKET
267 	const struct sockaddr_ll *sll;
268 #endif
269 
270 	if (getifaddrs(&ifaddrs) == -1)
271 		return NULL;
272 	ifs = malloc(sizeof(*ifs));
273 	if (ifs == NULL)
274 		return NULL;
275 	TAILQ_INIT(ifs);
276 
277 	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
278 		if (ifa->ifa_addr != NULL) {
279 #ifdef AF_LINK
280 			if (ifa->ifa_addr->sa_family != AF_LINK)
281 				continue;
282 #elif AF_PACKET
283 			if (ifa->ifa_addr->sa_family != AF_PACKET)
284 				continue;
285 #endif
286 		}
287 
288 		/* It's possible for an interface to have >1 AF_LINK.
289 		 * For our purposes, we use the first one. */
290 		TAILQ_FOREACH(ifp, ifs, next) {
291 			if (strcmp(ifp->name, ifa->ifa_name) == 0)
292 				break;
293 		}
294 		if (ifp)
295 			continue;
296 
297 		if (argc > 0) {
298 			for (i = 0; i < argc; i++) {
299 #ifdef __linux__
300 				/* Check the real interface name */
301 				strlcpy(ifn, argv[i], sizeof(ifn));
302 				p = strchr(ifn, ':');
303 				if (p)
304 					*p = '\0';
305 				if (strcmp(ifn, ifa->ifa_name) == 0)
306 					break;
307 #else
308 				if (strcmp(argv[i], ifa->ifa_name) == 0)
309 					break;
310 #endif
311 			}
312 			if (i == argc)
313 				continue;
314 			p = argv[i];
315 		} else {
316 			p = ifa->ifa_name;
317 #ifdef __linux__
318 			strlcpy(ifn, ifa->ifa_name, sizeof(ifn));
319 #endif
320 			/* -1 means we're discovering against a specific
321 			 * interface, but we still need the below rules
322 			 * to apply. */
323 			if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
324 				continue;
325 		}
326 		for (i = 0; i < ctx->ifdc; i++)
327 			if (!fnmatch(ctx->ifdv[i], p, 0))
328 				break;
329 		if (i < ctx->ifdc)
330 			continue;
331 		for (i = 0; i < ctx->ifac; i++)
332 			if (!fnmatch(ctx->ifav[i], p, 0))
333 				break;
334 		if (ctx->ifac && i == ctx->ifac)
335 			continue;
336 
337 		/* Ensure that the interface name has settled */
338 		if (!dev_initialized(ctx, p))
339 			continue;
340 
341 		/* Don't allow loopback or pointopoint unless explicit */
342 		if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) {
343 			if ((argc == 0 || argc == -1) &&
344 			    ctx->ifac == 0 && !if_hasconf(ctx, p))
345 				continue;
346 		}
347 
348 		if (if_vimaster(ctx, p) == 1) {
349 			logger(ctx, argc ? LOG_ERR : LOG_DEBUG,
350 			    "%s: is a Virtual Interface Master, skipping", p);
351 			continue;
352 		}
353 
354 		ifp = calloc(1, sizeof(*ifp));
355 		if (ifp == NULL) {
356 			logger(ctx, LOG_ERR, "%s: %m", __func__);
357 			break;
358 		}
359 		ifp->ctx = ctx;
360 #ifdef __linux__
361 		strlcpy(ifp->name, ifn, sizeof(ifp->name));
362 		strlcpy(ifp->alias, p, sizeof(ifp->alias));
363 #else
364 		strlcpy(ifp->name, p, sizeof(ifp->name));
365 #endif
366 		ifp->flags = ifa->ifa_flags;
367 		ifp->carrier = if_carrier(ifp);
368 
369 		if (ifa->ifa_addr != NULL) {
370 #ifdef AF_LINK
371 			sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
372 
373 #ifdef IFLR_ACTIVE
374 			/* We need to check for active address */
375 			strlcpy(iflr.iflr_name, ifp->name,
376 			    sizeof(iflr.iflr_name));
377 			memcpy(&iflr.addr, ifa->ifa_addr,
378 			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
379 			iflr.flags = IFLR_PREFIX;
380 			iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
381 			if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 ||
382 			    !(iflr.flags & IFLR_ACTIVE))
383 			{
384 				if_free(ifp);
385 				continue;
386 			}
387 #endif
388 
389 			ifp->index = sdl->sdl_index;
390 			switch(sdl->sdl_type) {
391 #ifdef IFT_BRIDGE
392 			case IFT_BRIDGE: /* FALLTHROUGH */
393 #endif
394 #ifdef IFT_PPP
395 			case IFT_PPP: /* FALLTHROUGH */
396 #endif
397 #ifdef IFT_PROPVIRTUAL
398 			case IFT_PROPVIRTUAL: /* FALLTHROUGH */
399 #endif
400 #if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL)
401 				/* Don't allow unless explicit */
402 				if ((argc == 0 || argc == -1) &&
403 				    ctx->ifac == 0 &&
404 				    !if_hasconf(ctx, ifp->name))
405 				{
406 					logger(ifp->ctx, LOG_DEBUG,
407 					    "%s: ignoring due to"
408 					    " interface type and"
409 					    " no config",
410 					    ifp->name);
411 					if_free(ifp);
412 					continue;
413 				}
414 				/* FALLTHROUGH */
415 #endif
416 #ifdef IFT_L2VLAN
417 			case IFT_L2VLAN: /* FALLTHROUGH */
418 #endif
419 #ifdef IFT_L3IPVLAN
420 			case IFT_L3IPVLAN: /* FALLTHROUGH */
421 #endif
422 			case IFT_ETHER:
423 				ifp->family = ARPHRD_ETHER;
424 				break;
425 #ifdef IFT_IEEE1394
426 			case IFT_IEEE1394:
427 				ifp->family = ARPHRD_IEEE1394;
428 				break;
429 #endif
430 #ifdef IFT_INFINIBAND
431 			case IFT_INFINIBAND:
432 				ifp->family = ARPHRD_INFINIBAND;
433 				break;
434 #endif
435 			default:
436 				/* Don't allow unless explicit */
437 				if ((argc == 0 || argc == -1) &&
438 				    ctx->ifac == 0 &&
439 				    !if_hasconf(ctx, ifp->name))
440 				{
441 					if_free(ifp);
442 					continue;
443 				}
444 				logger(ifp->ctx, LOG_WARNING,
445 				    "%s: unsupported interface type %.2x",
446 				    ifp->name, sdl->sdl_type);
447 				/* Pretend it's ethernet */
448 				ifp->family = ARPHRD_ETHER;
449 				break;
450 			}
451 			ifp->hwlen = sdl->sdl_alen;
452 #ifndef CLLADDR
453 #  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
454 #endif
455 			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
456 #elif AF_PACKET
457 			sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
458 			ifp->index = (unsigned int)sll->sll_ifindex;
459 			ifp->family = sll->sll_hatype;
460 			ifp->hwlen = sll->sll_halen;
461 			if (ifp->hwlen != 0)
462 				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
463 #endif
464 		}
465 #ifdef __linux__
466 		/* PPP addresses on Linux don't have hardware addresses */
467 		else
468 			ifp->index = if_nametoindex(ifp->name);
469 #endif
470 
471 		/* We only work on ethernet by default */
472 		if (ifp->family != ARPHRD_ETHER) {
473 			if ((argc == 0 || argc == -1) &&
474 			    ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
475 			{
476 				if_free(ifp);
477 				continue;
478 			}
479 			switch (ifp->family) {
480 			case ARPHRD_IEEE1394:
481 			case ARPHRD_INFINIBAND:
482 #ifdef ARPHRD_LOOPBACK
483 			case ARPHRD_LOOPBACK:
484 #endif
485 #ifdef ARPHRD_PPP
486 			case ARPHRD_PPP:
487 #endif
488 				/* We don't warn for supported families */
489 				break;
490 
491 /* IFT already checked */
492 #ifndef AF_LINK
493 			default:
494 				logger(ifp->ctx, LOG_WARNING,
495 				    "%s: unsupported interface family %.2x",
496 				    ifp->name, ifp->family);
497 				break;
498 #endif
499 			}
500 		}
501 
502 		if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
503 			/* Handle any platform init for the interface */
504 			if (if_init(ifp) == -1) {
505 				logger(ifp->ctx, LOG_ERR, "%s: if_init: %m", p);
506 				if_free(ifp);
507 				continue;
508 			}
509 
510 			/* Ensure that the MTU is big enough for DHCP */
511 			if (if_getmtu(ifp) < MTU_MIN &&
512 			    if_setmtu(ifp, MTU_MIN) == -1)
513 			{
514 				logger(ifp->ctx, LOG_ERR,
515 				    "%s: if_setmtu: %m", p);
516 				if_free(ifp);
517 				continue;
518 			}
519 		}
520 
521 #ifdef SIOCGIFPRIORITY
522 		/* Respect the interface priority */
523 		memset(&ifr, 0, sizeof(ifr));
524 		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
525 		if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
526 			ifp->metric = ifr.ifr_metric;
527 #else
528 		/* We reserve the 100 range for virtual interfaces, if and when
529 		 * we can work them out. */
530 		ifp->metric = 200 + ifp->index;
531 		if (if_getssid(ifp) != -1) {
532 			ifp->wireless = 1;
533 			ifp->metric += 100;
534 		}
535 #endif
536 
537 		TAILQ_INSERT_TAIL(ifs, ifp, next);
538 	}
539 
540 	if_learnaddrs1(ctx, ifs, ifaddrs);
541 	freeifaddrs(ifaddrs);
542 
543 	return ifs;
544 }
545 
546 static struct interface *
if_findindexname(struct if_head * ifaces,unsigned int idx,const char * name)547 if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
548 {
549 
550 	if (ifaces != NULL) {
551 		struct interface *ifp;
552 
553 		TAILQ_FOREACH(ifp, ifaces, next) {
554 			if ((name && strcmp(ifp->name, name) == 0) ||
555 #ifdef __linux__
556 			    (name && strcmp(ifp->alias, name) == 0) ||
557 #endif
558 			    (!name && ifp->index == idx))
559 				return ifp;
560 		}
561 	}
562 
563 	errno = ESRCH;
564 	return NULL;
565 }
566 
567 struct interface *
if_find(struct if_head * ifaces,const char * name)568 if_find(struct if_head *ifaces, const char *name)
569 {
570 
571 	return if_findindexname(ifaces, 0, name);
572 }
573 
574 struct interface *
if_findindex(struct if_head * ifaces,unsigned int idx)575 if_findindex(struct if_head *ifaces, unsigned int idx)
576 {
577 
578 	return if_findindexname(ifaces, idx, NULL);
579 }
580 
581 int
if_domtu(const struct interface * ifp,short int mtu)582 if_domtu(const struct interface *ifp, short int mtu)
583 {
584 	int r;
585 	struct ifreq ifr;
586 
587 	memset(&ifr, 0, sizeof(ifr));
588 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
589 	ifr.ifr_mtu = mtu;
590 	r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
591 	if (r == -1)
592 		return -1;
593 	return ifr.ifr_mtu;
594 }
595 
596 /* Interface comparer for working out ordering. */
597 static int
if_cmp(const struct interface * si,const struct interface * ti)598 if_cmp(const struct interface *si, const struct interface *ti)
599 {
600 #ifdef INET
601 	int r;
602 #endif
603 
604 	/* Check carrier status first */
605 	if (si->carrier > ti->carrier)
606 		return -1;
607 	if (si->carrier < ti->carrier)
608 		return 1;
609 
610 	if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
611 		return -1;
612 	if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
613 		return 1;
614 	if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti))
615 		return -1;
616 	if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti))
617 		return 1;
618 	if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti))
619 		return -1;
620 	if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti))
621 		return 1;
622 
623 #ifdef INET
624 	/* Special attention needed here due to states and IPv4LL. */
625 	if ((r = ipv4_ifcmp(si, ti)) != 0)
626 		return r;
627 #endif
628 
629 	/* Finally, metric */
630 	if (si->metric < ti->metric)
631 		return -1;
632 	if (si->metric > ti->metric)
633 		return 1;
634 	return 0;
635 }
636 
637 /* Sort the interfaces into a preferred order - best first, worst last. */
638 void
if_sortinterfaces(struct dhcpcd_ctx * ctx)639 if_sortinterfaces(struct dhcpcd_ctx *ctx)
640 {
641 	struct if_head sorted;
642 	struct interface *ifp, *ift;
643 
644 	if (ctx->ifaces == NULL ||
645 	    (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL ||
646 	    TAILQ_NEXT(ifp, next) == NULL)
647 		return;
648 
649 	TAILQ_INIT(&sorted);
650 	TAILQ_REMOVE(ctx->ifaces, ifp, next);
651 	TAILQ_INSERT_HEAD(&sorted, ifp, next);
652 	while ((ifp = TAILQ_FIRST(ctx->ifaces))) {
653 		TAILQ_REMOVE(ctx->ifaces, ifp, next);
654 		TAILQ_FOREACH(ift, &sorted, next) {
655 			if (if_cmp(ifp, ift) == -1) {
656 				TAILQ_INSERT_BEFORE(ift, ifp, next);
657 				break;
658 			}
659 		}
660 		if (ift == NULL)
661 			TAILQ_INSERT_TAIL(&sorted, ifp, next);
662 	}
663 	TAILQ_CONCAT(ctx->ifaces, &sorted, next);
664 }
665 
666 int
xsocket(int domain,int type,int protocol,int flags)667 xsocket(int domain, int type, int protocol, int flags)
668 {
669 #ifdef SOCK_CLOEXEC
670 	if (flags & O_CLOEXEC)
671 		type |= SOCK_CLOEXEC;
672 	if (flags & O_NONBLOCK)
673 		type |= SOCK_NONBLOCK;
674 
675 	return socket(domain, type, protocol);
676 #else
677 	int s, xflags;
678 
679 	if ((s = socket(domain, type, protocol)) == -1)
680 		return -1;
681 	if ((flags & O_CLOEXEC) && (xflags = fcntl(s, F_GETFD, 0)) == -1 ||
682 	    fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1)
683 		goto out;
684 	if ((flags & O_NONBLOCK) && (xflags = fcntl(s, F_GETFL, 0)) == -1 ||
685 	    fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1)
686 		goto out;
687 	return s;
688 out:
689 	close(s);
690 	return -1;
691 #endif
692 }
693