if.c revision 1.1.1.6
1/* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2018 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 "config.h" 34 35#include <net/if.h> 36#include <net/if_arp.h> 37#include <netinet/in.h> 38#ifdef AF_LINK 39# include <net/if_dl.h> 40# include <net/if_types.h> 41# include <netinet/in_var.h> 42# undef AF_PACKET /* Newer Illumos defines this */ 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 <inttypes.h> 56#include <fnmatch.h> 57#include <stddef.h> 58#include <stdio.h> 59#include <stdlib.h> 60#include <string.h> 61#include <unistd.h> 62#include <fcntl.h> 63 64#include "common.h" 65#include "dev.h" 66#include "dhcp.h" 67#include "dhcp6.h" 68#include "if.h" 69#include "if-options.h" 70#include "ipv4.h" 71#include "ipv4ll.h" 72#include "ipv6nd.h" 73#include "logerr.h" 74 75void 76if_free(struct interface *ifp) 77{ 78 79 if (ifp == NULL) 80 return; 81 ipv4ll_free(ifp); 82 dhcp_free(ifp); 83 ipv4_free(ifp); 84 dhcp6_free(ifp); 85 ipv6nd_free(ifp); 86 ipv6_free(ifp); 87 rt_freeif(ifp); 88 free_options(ifp->options); 89 free(ifp); 90} 91 92int 93if_opensockets(struct dhcpcd_ctx *ctx) 94{ 95 96 if (if_opensockets_os(ctx) == -1) 97 return -1; 98 99 /* We use this socket for some operations without INET. */ 100 ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); 101 if (ctx->pf_inet_fd == -1) 102 return -1; 103 104#ifdef IFLR_ACTIVE 105 ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0); 106 if (ctx->pf_link_fd == -1) 107 return -1; 108#endif 109 110 return 0; 111} 112 113void 114if_closesockets(struct dhcpcd_ctx *ctx) 115{ 116 117 if (ctx->pf_inet_fd != -1) 118 close(ctx->pf_inet_fd); 119#ifdef IFLR_ACTIVE 120 if (ctx->pf_link_fd != -1) 121 close(ctx->pf_link_fd); 122#endif 123 124 if (ctx->priv) { 125 if_closesockets_os(ctx); 126 free(ctx->priv); 127 } 128} 129 130int 131if_carrier(struct interface *ifp) 132{ 133 int r; 134 struct ifreq ifr; 135#ifdef SIOCGIFMEDIA 136 struct ifmediareq ifmr; 137#endif 138 139 memset(&ifr, 0, sizeof(ifr)); 140 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 141 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1) 142 return LINK_UNKNOWN; 143 ifp->flags = (unsigned int)ifr.ifr_flags; 144 145#ifdef SIOCGIFMEDIA 146 memset(&ifmr, 0, sizeof(ifmr)); 147 strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name)); 148 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) != -1 && 149 ifmr.ifm_status & IFM_AVALID) 150 r = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN; 151 else 152 r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN; 153#else 154 r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN; 155#endif 156 return r; 157} 158 159int 160if_setflag(struct interface *ifp, short flag) 161{ 162 struct ifreq ifr; 163 int r; 164 165 memset(&ifr, 0, sizeof(ifr)); 166 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 167 r = -1; 168 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == 0) { 169 if (flag == 0 || (ifr.ifr_flags & flag) == flag) 170 r = 0; 171 else { 172 ifr.ifr_flags |= flag; 173 if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) ==0) 174 r = 0; 175 } 176 ifp->flags = (unsigned int)ifr.ifr_flags; 177 } 178 return r; 179} 180 181static int 182if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname) 183{ 184 int i; 185 186 for (i = 0; i < ctx->ifcc; i++) { 187 if (strcmp(ctx->ifcv[i], ifname) == 0) 188 return 1; 189 } 190 return 0; 191} 192 193void 194if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs, 195 struct ifaddrs **ifaddrs) 196{ 197 struct ifaddrs *ifa; 198 struct interface *ifp; 199#ifdef INET 200 const struct sockaddr_in *addr, *net, *brd; 201#endif 202#ifdef INET6 203 struct sockaddr_in6 *sin6, *net6; 204#endif 205 int addrflags; 206 207 for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) { 208 if (ifa->ifa_addr == NULL) 209 continue; 210 if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL) 211 continue; 212#ifdef HAVE_IFADDRS_ADDRFLAGS 213 addrflags = (int)ifa->ifa_addrflags; 214#endif 215 switch(ifa->ifa_addr->sa_family) { 216#ifdef INET 217 case AF_INET: 218 addr = (void *)ifa->ifa_addr; 219 net = (void *)ifa->ifa_netmask; 220 if (ifa->ifa_flags & IFF_POINTOPOINT) 221 brd = (void *)ifa->ifa_dstaddr; 222 else 223 brd = (void *)ifa->ifa_broadaddr; 224#ifndef HAVE_IFADDRS_ADDRFLAGS 225 addrflags = if_addrflags(ifp, &addr->sin_addr, 226 ifa->ifa_name); 227 if (addrflags == -1) { 228 if (errno != EEXIST) 229 logerr("%s: if_addrflags: %s", 230 __func__, 231 inet_ntoa(addr->sin_addr)); 232 continue; 233 } 234#endif 235 ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name, 236 &addr->sin_addr, &net->sin_addr, 237 brd ? &brd->sin_addr : NULL, addrflags); 238 break; 239#endif 240#ifdef INET6 241 case AF_INET6: 242 sin6 = (void *)ifa->ifa_addr; 243 net6 = (void *)ifa->ifa_netmask; 244#ifdef __KAME__ 245 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 246 /* Remove the scope from the address */ 247 sin6->sin6_addr.s6_addr[2] = 248 sin6->sin6_addr.s6_addr[3] = '\0'; 249#endif 250#ifndef HAVE_IFADDRS_ADDRFLAGS 251 addrflags = if_addrflags6(ifp, &sin6->sin6_addr, 252 ifa->ifa_name); 253 if (addrflags == -1) { 254 if (errno != EEXIST) 255 logerr("%s: if_addrflags6", __func__); 256 continue; 257 } 258#endif 259 ipv6_handleifa(ctx, RTM_NEWADDR, ifs, 260 ifa->ifa_name, &sin6->sin6_addr, 261 ipv6_prefixlen(&net6->sin6_addr), addrflags); 262 break; 263#endif 264 } 265 } 266 267 freeifaddrs(*ifaddrs); 268 *ifaddrs = NULL; 269} 270 271bool 272if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen) 273{ 274 size_t i; 275 bool all_zeros, all_ones; 276 277 all_zeros = all_ones = true; 278 for (i = 0; i < hwlen; i++) { 279 if (hwaddr[i] != 0x00) 280 all_zeros = false; 281 if (hwaddr[i] != 0xff) 282 all_ones = false; 283 if (!all_zeros && !all_ones) 284 return true; 285 } 286 return false; 287} 288 289struct if_head * 290if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs, 291 int argc, char * const *argv) 292{ 293 struct ifaddrs *ifa; 294 int i; 295 unsigned int active; 296 struct if_head *ifs; 297 struct interface *ifp; 298 struct if_spec spec; 299#ifdef AF_LINK 300 const struct sockaddr_dl *sdl; 301#ifdef SIOCGIFPRIORITY 302 struct ifreq ifr; 303#endif 304#ifdef IFLR_ACTIVE 305 struct if_laddrreq iflr; 306#endif 307 308#ifdef IFLR_ACTIVE 309 memset(&iflr, 0, sizeof(iflr)); 310#endif 311#elif AF_PACKET 312 const struct sockaddr_ll *sll; 313#endif 314 315 if ((ifs = malloc(sizeof(*ifs))) == NULL) { 316 logerr(__func__); 317 return NULL; 318 } 319 TAILQ_INIT(ifs); 320 if (getifaddrs(ifaddrs) == -1) { 321 logerr(__func__); 322 goto out; 323 } 324 325 for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) { 326 if (ifa->ifa_addr != NULL) { 327#ifdef AF_LINK 328 if (ifa->ifa_addr->sa_family != AF_LINK) 329 continue; 330#elif AF_PACKET 331 if (ifa->ifa_addr->sa_family != AF_PACKET) 332 continue; 333#endif 334 } 335 if (if_nametospec(ifa->ifa_name, &spec) != 0) 336 continue; 337 338 /* It's possible for an interface to have >1 AF_LINK. 339 * For our purposes, we use the first one. */ 340 TAILQ_FOREACH(ifp, ifs, next) { 341 if (strcmp(ifp->name, spec.devname) == 0) 342 break; 343 } 344 if (ifp) 345 continue; 346 347 if (argc > 0) { 348 for (i = 0; i < argc; i++) { 349 if (strcmp(argv[i], spec.devname) == 0) 350 break; 351 } 352 active = (i == argc) ? IF_INACTIVE : IF_ACTIVE_USER; 353 } else { 354 /* -1 means we're discovering against a specific 355 * interface, but we still need the below rules 356 * to apply. */ 357 if (argc == -1 && strcmp(argv[0], spec.devname) != 0) 358 continue; 359 active = ctx->options & DHCPCD_INACTIVE ? 360 IF_INACTIVE: IF_ACTIVE_USER; 361 } 362 363 for (i = 0; i < ctx->ifdc; i++) 364 if (fnmatch(ctx->ifdv[i], spec.devname, 0) == 0) 365 break; 366 if (i < ctx->ifdc) 367 active = IF_INACTIVE; 368 for (i = 0; i < ctx->ifc; i++) 369 if (fnmatch(ctx->ifv[i], spec.devname, 0) == 0) 370 break; 371 if (ctx->ifc && i == ctx->ifc) 372 active = IF_INACTIVE; 373 for (i = 0; i < ctx->ifac; i++) 374 if (fnmatch(ctx->ifav[i], spec.devname, 0) == 0) 375 break; 376 if (ctx->ifac && i == ctx->ifac) 377 active = IF_INACTIVE; 378 379#ifdef PLUGIN_DEV 380 /* Ensure that the interface name has settled */ 381 if (!dev_initialized(ctx, spec.devname)) 382 continue; 383#endif 384 385 /* Don't allow loopback or pointopoint unless explicit */ 386 if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) { 387 if ((argc == 0 || argc == -1) && 388 ctx->ifac == 0 && !if_hasconf(ctx, spec.devname)) 389 active = IF_INACTIVE; 390 } 391 392 if (if_vimaster(ctx, spec.devname) == 1) { 393 logfunc_t *logfunc = argc != 0 ? logerrx : logdebugx; 394 logfunc("%s: is a Virtual Interface Master, skipping", 395 spec.devname); 396 continue; 397 } 398 399 ifp = calloc(1, sizeof(*ifp)); 400 if (ifp == NULL) { 401 logerr(__func__); 402 break; 403 } 404 ifp->ctx = ctx; 405 strlcpy(ifp->name, spec.devname, sizeof(ifp->name)); 406 ifp->flags = ifa->ifa_flags; 407 408 if (ifa->ifa_addr != NULL) { 409#ifdef AF_LINK 410 sdl = (const void *)ifa->ifa_addr; 411 412#ifdef IFLR_ACTIVE 413 /* We need to check for active address */ 414 strlcpy(iflr.iflr_name, ifp->name, 415 sizeof(iflr.iflr_name)); 416 memcpy(&iflr.addr, ifa->ifa_addr, 417 MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr))); 418 iflr.flags = IFLR_PREFIX; 419 iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY; 420 if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 || 421 !(iflr.flags & IFLR_ACTIVE)) 422 { 423 if_free(ifp); 424 continue; 425 } 426#endif 427 428 ifp->index = sdl->sdl_index; 429 switch(sdl->sdl_type) { 430#ifdef IFT_BRIDGE 431 case IFT_BRIDGE: /* FALLTHROUGH */ 432#endif 433#ifdef IFT_PPP 434 case IFT_PPP: /* FALLTHROUGH */ 435#endif 436#ifdef IFT_PROPVIRTUAL 437 case IFT_PROPVIRTUAL: /* FALLTHROUGH */ 438#endif 439#if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL) 440 /* Don't allow unless explicit */ 441 if ((argc == 0 || argc == -1) && 442 ctx->ifac == 0 && active && 443 !if_hasconf(ctx, ifp->name)) 444 { 445 logdebugx("%s: ignoring due to" 446 " interface type and" 447 " no config", 448 ifp->name); 449 active = IF_INACTIVE; 450 } 451 /* FALLTHROUGH */ 452#endif 453#ifdef IFT_L2VLAN 454 case IFT_L2VLAN: /* FALLTHROUGH */ 455#endif 456#ifdef IFT_L3IPVLAN 457 case IFT_L3IPVLAN: /* FALLTHROUGH */ 458#endif 459 case IFT_ETHER: 460 ifp->family = ARPHRD_ETHER; 461 break; 462#ifdef IFT_IEEE1394 463 case IFT_IEEE1394: 464 ifp->family = ARPHRD_IEEE1394; 465 break; 466#endif 467#ifdef IFT_INFINIBAND 468 case IFT_INFINIBAND: 469 ifp->family = ARPHRD_INFINIBAND; 470 break; 471#endif 472 default: 473 /* Don't allow unless explicit */ 474 if ((argc == 0 || argc == -1) && 475 ctx->ifac == 0 && 476 !if_hasconf(ctx, ifp->name)) 477 active = IF_INACTIVE; 478 if (active) 479 logwarnx("%s: unsupported" 480 " interface type %.2x", 481 ifp->name, sdl->sdl_type); 482 /* Pretend it's ethernet */ 483 ifp->family = ARPHRD_ETHER; 484 break; 485 } 486 ifp->hwlen = sdl->sdl_alen; 487 memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen); 488#elif AF_PACKET 489 sll = (const 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 /* Ensure hardware address is valid. */ 504 if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen)) 505 ifp->hwlen = 0; 506 507 /* We only work on ethernet by default */ 508 if (ifp->family != ARPHRD_ETHER) { 509 if ((argc == 0 || argc == -1) && 510 ctx->ifac == 0 && !if_hasconf(ctx, ifp->name)) 511 active = IF_INACTIVE; 512 switch (ifp->family) { 513 case ARPHRD_IEEE1394: 514 case ARPHRD_INFINIBAND: 515#ifdef ARPHRD_LOOPBACK 516 case ARPHRD_LOOPBACK: 517#endif 518#ifdef ARPHRD_PPP 519 case ARPHRD_PPP: 520#endif 521 /* We don't warn for supported families */ 522 break; 523 524/* IFT already checked */ 525#ifndef AF_LINK 526 default: 527 if (active) 528 logwarnx("%s: unsupported" 529 " interface family %.2x", 530 ifp->name, ifp->family); 531 break; 532#endif 533 } 534 } 535 536 if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) { 537 /* Handle any platform init for the interface */ 538 if (active != IF_INACTIVE && if_init(ifp) == -1) { 539 logerr("%s: if_init", ifp->name); 540 if_free(ifp); 541 continue; 542 } 543 } 544 545 ifp->vlanid = if_vlanid(ifp); 546 547#ifdef SIOCGIFPRIORITY 548 /* Respect the interface priority */ 549 memset(&ifr, 0, sizeof(ifr)); 550 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 551 if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0) 552 ifp->metric = (unsigned int)ifr.ifr_metric; 553 if_getssid(ifp); 554#else 555 /* We reserve the 100 range for virtual interfaces, if and when 556 * we can work them out. */ 557 ifp->metric = 200 + ifp->index; 558 if (if_getssid(ifp) != -1) { 559 ifp->wireless = 1; 560 ifp->metric += 100; 561 } 562#endif 563 564 ifp->active = active; 565 if (ifp->active) 566 ifp->carrier = if_carrier(ifp); 567 else 568 ifp->carrier = LINK_UNKNOWN; 569 TAILQ_INSERT_TAIL(ifs, ifp, next); 570 } 571 572out: 573 return ifs; 574} 575 576/* Decode bge0:1 as dev = bge, ppa = 0 and lun = 1 */ 577int 578if_nametospec(const char *ifname, struct if_spec *spec) 579{ 580 char *ep; 581 int e; 582 583 if (ifname == NULL || *ifname == '\0' || 584 strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >= 585 sizeof(spec->ifname) || 586 strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >= 587 sizeof(spec->drvname)) 588 { 589 errno = EINVAL; 590 return -1; 591 } 592 ep = strchr(spec->drvname, ':'); 593 if (ep) { 594 spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e); 595 if (e != 0) { 596 errno = e; 597 return -1; 598 } 599 *ep-- = '\0'; 600 } else { 601 spec->lun = -1; 602 ep = spec->drvname + strlen(spec->drvname) - 1; 603 } 604 strlcpy(spec->devname, spec->drvname, sizeof(spec->devname)); 605 while (ep > spec->drvname && isdigit((int)*ep)) 606 ep--; 607 if (*ep++ == ':') { 608 errno = EINVAL; 609 return -1; 610 } 611 spec->ppa = (int)strtoi(ep, NULL, 10, 0, INT_MAX, &e); 612 if (e != 0) 613 spec->ppa = -1; 614 *ep = '\0'; 615 616 return 0; 617} 618 619static struct interface * 620if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name) 621{ 622 623 if (ifaces != NULL) { 624 struct if_spec spec; 625 struct interface *ifp; 626 627 if (name && if_nametospec(name, &spec) == -1) 628 return NULL; 629 630 TAILQ_FOREACH(ifp, ifaces, next) { 631 if ((name && strcmp(ifp->name, spec.devname) == 0) || 632 (!name && ifp->index == idx)) 633 return ifp; 634 } 635 } 636 637 errno = ENXIO; 638 return NULL; 639} 640 641struct interface * 642if_find(struct if_head *ifaces, const char *name) 643{ 644 645 return if_findindexname(ifaces, 0, name); 646} 647 648struct interface * 649if_findindex(struct if_head *ifaces, unsigned int idx) 650{ 651 652 return if_findindexname(ifaces, idx, NULL); 653} 654 655struct interface * 656if_loopback(struct dhcpcd_ctx *ctx) 657{ 658 struct interface *ifp; 659 660 TAILQ_FOREACH(ifp, ctx->ifaces, next) { 661 if (ifp->flags & IFF_LOOPBACK) 662 return ifp; 663 } 664 return NULL; 665} 666 667int 668if_domtu(const struct interface *ifp, short int mtu) 669{ 670 int r; 671 struct ifreq ifr; 672 673 memset(&ifr, 0, sizeof(ifr)); 674 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 675 ifr.ifr_mtu = mtu; 676 r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr); 677 if (r == -1) 678 return -1; 679 return ifr.ifr_mtu; 680} 681 682/* Interface comparer for working out ordering. */ 683static int 684if_cmp(const struct interface *si, const struct interface *ti) 685{ 686#ifdef INET 687 int r; 688#endif 689 690 /* Check active first */ 691 if (si->active > ti->active) 692 return -1; 693 if (si->active < ti->active) 694 return 1; 695 696 /* Check carrier status next */ 697 if (si->carrier > ti->carrier) 698 return -1; 699 if (si->carrier < ti->carrier) 700 return 1; 701 702 if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti)) 703 return -1; 704 if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti)) 705 return 1; 706 if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti)) 707 return -1; 708 if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti)) 709 return 1; 710 if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti)) 711 return -1; 712 if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti)) 713 return 1; 714 715#ifdef INET 716 /* Special attention needed here due to states and IPv4LL. */ 717 if ((r = ipv4_ifcmp(si, ti)) != 0) 718 return r; 719#endif 720 721 /* Finally, metric */ 722 if (si->metric < ti->metric) 723 return -1; 724 if (si->metric > ti->metric) 725 return 1; 726 return 0; 727} 728 729/* Sort the interfaces into a preferred order - best first, worst last. */ 730void 731if_sortinterfaces(struct dhcpcd_ctx *ctx) 732{ 733 struct if_head sorted; 734 struct interface *ifp, *ift; 735 736 if (ctx->ifaces == NULL || 737 (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL || 738 TAILQ_NEXT(ifp, next) == NULL) 739 return; 740 741 TAILQ_INIT(&sorted); 742 TAILQ_REMOVE(ctx->ifaces, ifp, next); 743 TAILQ_INSERT_HEAD(&sorted, ifp, next); 744 while ((ifp = TAILQ_FIRST(ctx->ifaces))) { 745 TAILQ_REMOVE(ctx->ifaces, ifp, next); 746 TAILQ_FOREACH(ift, &sorted, next) { 747 if (if_cmp(ifp, ift) == -1) { 748 TAILQ_INSERT_BEFORE(ift, ifp, next); 749 break; 750 } 751 } 752 if (ift == NULL) 753 TAILQ_INSERT_TAIL(&sorted, ifp, next); 754 } 755 TAILQ_CONCAT(ctx->ifaces, &sorted, next); 756} 757 758int 759xsocket(int domain, int type, int protocol) 760{ 761 int s; 762#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK) 763 int xflags, xtype = type; 764#endif 765 766#ifndef HAVE_SOCK_CLOEXEC 767 if (xtype & SOCK_CLOEXEC) 768 type &= ~SOCK_CLOEXEC; 769#endif 770#ifndef HAVE_SOCK_NONBLOCK 771 if (xtype & SOCK_NONBLOCK) 772 type &= ~SOCK_NONBLOCK; 773#endif 774 775 if ((s = socket(domain, type, protocol)) == -1) 776 return -1; 777 778#ifndef HAVE_SOCK_CLOEXEC 779 if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 || 780 fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1)) 781 goto out; 782#endif 783#ifndef HAVE_SOCK_NONBLOCK 784 if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 || 785 fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1)) 786 goto out; 787#endif 788 789 return s; 790 791#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK) 792out: 793 close(s); 794 return -1; 795#endif 796} 797