Home | History | Annotate | Download | only in dhcpcd-6.8.2
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2015 Roy Marples <roy (at) 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
     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
    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
    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
    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
    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 
    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 *
    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 *
    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 *
    614 if_find(struct if_head *ifaces, const char *name)
    615 {
    616 
    617 	return if_findindexname(ifaces, 0, name);
    618 }
    619 
    620 struct interface *
    621 if_findindex(struct if_head *ifaces, unsigned int idx)
    622 {
    623 
    624 	return if_findindexname(ifaces, idx, NULL);
    625 }
    626 
    627 int
    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
    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
    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