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