if.c revision 1.1.1.2
1/* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2017 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 193static void if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs, 194 struct ifaddrs *ifaddrs) 195{ 196 struct ifaddrs *ifa; 197 struct interface *ifp; 198#ifdef INET 199 const struct sockaddr_in *addr, *net, *brd; 200#endif 201#ifdef INET6 202 struct sockaddr_in6 *sin6, *net6; 203#endif 204 int addrflags; 205 206 for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { 207 if (ifa->ifa_addr == NULL) 208 continue; 209 if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL) 210 continue; 211#ifdef HAVE_IFADDRS_ADDRFLAGS 212 addrflags = (int)ifa->ifa_addrflags; 213#endif 214 switch(ifa->ifa_addr->sa_family) { 215#ifdef INET 216 case AF_INET: 217 addr = (void *)ifa->ifa_addr; 218 net = (void *)ifa->ifa_netmask; 219 if (ifa->ifa_flags & IFF_POINTOPOINT) 220 brd = (void *)ifa->ifa_dstaddr; 221 else 222 brd = (void *)ifa->ifa_broadaddr; 223#ifndef HAVE_IFADDRS_ADDRFLAGS 224 addrflags = if_addrflags(ifp, &addr->sin_addr, 225 ifa->ifa_name); 226 if (addrflags == -1) { 227 if (errno != EEXIST) 228 logerr("%s: if_addrflags: %s", 229 __func__, 230 inet_ntoa(addr->sin_addr)); 231 continue; 232 } 233#endif 234 ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name, 235 &addr->sin_addr, &net->sin_addr, 236 brd ? &brd->sin_addr : NULL, addrflags); 237 break; 238#endif 239#ifdef INET6 240 case AF_INET6: 241 sin6 = (void *)ifa->ifa_addr; 242 net6 = (void *)ifa->ifa_netmask; 243#ifdef __KAME__ 244 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 245 /* Remove the scope from the address */ 246 sin6->sin6_addr.s6_addr[2] = 247 sin6->sin6_addr.s6_addr[3] = '\0'; 248#endif 249#ifndef HAVE_IFADDRS_ADDRFLAGS 250 addrflags = if_addrflags6(ifp, &sin6->sin6_addr, 251 ifa->ifa_name); 252 if (addrflags == -1) { 253 if (errno != EEXIST) 254 logerr("%s: if_addrflags6", __func__); 255 continue; 256 } 257#endif 258 ipv6_handleifa(ctx, RTM_NEWADDR, ifs, 259 ifa->ifa_name, &sin6->sin6_addr, 260 ipv6_prefixlen(&net6->sin6_addr), addrflags); 261 break; 262#endif 263 } 264 } 265} 266 267struct if_head * 268if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv) 269{ 270 struct ifaddrs *ifaddrs, *ifa; 271 int i; 272 unsigned int active; 273 struct if_head *ifs; 274 struct interface *ifp; 275 struct if_spec spec; 276#ifdef AF_LINK 277 const struct sockaddr_dl *sdl; 278#ifdef SIOCGIFPRIORITY 279 struct ifreq ifr; 280#endif 281#ifdef IFLR_ACTIVE 282 struct if_laddrreq iflr; 283#endif 284 285#ifdef IFLR_ACTIVE 286 memset(&iflr, 0, sizeof(iflr)); 287#endif 288#elif AF_PACKET 289 const struct sockaddr_ll *sll; 290#endif 291 292 if (getifaddrs(&ifaddrs) == -1) 293 return NULL; 294 295 if ((ifs = malloc(sizeof(*ifs))) == NULL) 296 goto failed; 297 TAILQ_INIT(ifs); 298 299 for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { 300 if (ifa->ifa_addr != NULL) { 301#ifdef AF_LINK 302 if (ifa->ifa_addr->sa_family != AF_LINK) 303 continue; 304#elif AF_PACKET 305 if (ifa->ifa_addr->sa_family != AF_PACKET) 306 continue; 307#endif 308 } 309 if (if_nametospec(ifa->ifa_name, &spec) != 0) 310 continue; 311 312 /* It's possible for an interface to have >1 AF_LINK. 313 * For our purposes, we use the first one. */ 314 TAILQ_FOREACH(ifp, ifs, next) { 315 if (strcmp(ifp->name, spec.devname) == 0) 316 break; 317 } 318 if (ifp) 319 continue; 320 321 if (argc > 0) { 322 for (i = 0; i < argc; i++) { 323 if (strcmp(argv[i], spec.devname) == 0) 324 break; 325 } 326 active = (i == argc) ? IF_INACTIVE : IF_ACTIVE_USER; 327 } else { 328 /* -1 means we're discovering against a specific 329 * interface, but we still need the below rules 330 * to apply. */ 331 if (argc == -1 && strcmp(argv[0], spec.devname) != 0) 332 continue; 333 active = ctx->options & DHCPCD_INACTIVE ? 334 IF_INACTIVE: IF_ACTIVE_USER; 335 } 336 337 for (i = 0; i < ctx->ifdc; i++) 338 if (!fnmatch(ctx->ifdv[i], spec.devname, 0)) 339 break; 340 if (i < ctx->ifdc) 341 active = IF_INACTIVE; 342 for (i = 0; i < ctx->ifac; i++) 343 if (!fnmatch(ctx->ifav[i], spec.devname, 0)) 344 break; 345 if (ctx->ifac && i == ctx->ifac) 346 active = IF_INACTIVE; 347 348#ifdef PLUGIN_DEV 349 /* Ensure that the interface name has settled */ 350 if (!dev_initialized(ctx, spec.devname)) 351 continue; 352#endif 353 354 /* Don't allow loopback or pointopoint unless explicit */ 355 if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) { 356 if ((argc == 0 || argc == -1) && 357 ctx->ifac == 0 && !if_hasconf(ctx, spec.devname)) 358 active = IF_INACTIVE; 359 } 360 361 if (if_vimaster(ctx, spec.devname) == 1) { 362 logfunc_t *logfunc = argc != 0 ? logerrx : logdebugx; 363 logfunc("%s: is a Virtual Interface Master, skipping", 364 spec.devname); 365 continue; 366 } 367 368 ifp = calloc(1, sizeof(*ifp)); 369 if (ifp == NULL) { 370 logerr(__func__); 371 break; 372 } 373 ifp->ctx = ctx; 374 strlcpy(ifp->name, spec.devname, sizeof(ifp->name)); 375 ifp->flags = ifa->ifa_flags; 376 377 if (ifa->ifa_addr != NULL) { 378#ifdef AF_LINK 379 sdl = (const void *)ifa->ifa_addr; 380 381#ifdef IFLR_ACTIVE 382 /* We need to check for active address */ 383 strlcpy(iflr.iflr_name, ifp->name, 384 sizeof(iflr.iflr_name)); 385 memcpy(&iflr.addr, ifa->ifa_addr, 386 MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr))); 387 iflr.flags = IFLR_PREFIX; 388 iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY; 389 if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 || 390 !(iflr.flags & IFLR_ACTIVE)) 391 { 392 if_free(ifp); 393 continue; 394 } 395#endif 396 397 ifp->index = sdl->sdl_index; 398 switch(sdl->sdl_type) { 399#ifdef IFT_BRIDGE 400 case IFT_BRIDGE: /* FALLTHROUGH */ 401#endif 402#ifdef IFT_PPP 403 case IFT_PPP: /* FALLTHROUGH */ 404#endif 405#ifdef IFT_PROPVIRTUAL 406 case IFT_PROPVIRTUAL: /* FALLTHROUGH */ 407#endif 408#if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL) 409 /* Don't allow unless explicit */ 410 if ((argc == 0 || argc == -1) && 411 ctx->ifac == 0 && active && 412 !if_hasconf(ctx, ifp->name)) 413 { 414 logdebugx("%s: ignoring due to" 415 " interface type and" 416 " no config", 417 ifp->name); 418 active = IF_INACTIVE; 419 } 420 /* FALLTHROUGH */ 421#endif 422#ifdef IFT_L2VLAN 423 case IFT_L2VLAN: /* FALLTHROUGH */ 424#endif 425#ifdef IFT_L3IPVLAN 426 case IFT_L3IPVLAN: /* FALLTHROUGH */ 427#endif 428 case IFT_ETHER: 429 ifp->family = ARPHRD_ETHER; 430 break; 431#ifdef IFT_IEEE1394 432 case IFT_IEEE1394: 433 ifp->family = ARPHRD_IEEE1394; 434 break; 435#endif 436#ifdef IFT_INFINIBAND 437 case IFT_INFINIBAND: 438 ifp->family = ARPHRD_INFINIBAND; 439 break; 440#endif 441 default: 442 /* Don't allow unless explicit */ 443 if ((argc == 0 || argc == -1) && 444 ctx->ifac == 0 && 445 !if_hasconf(ctx, ifp->name)) 446 active = IF_INACTIVE; 447 if (active) 448 logwarnx("%s: unsupported" 449 " interface type %.2x", 450 ifp->name, sdl->sdl_type); 451 /* Pretend it's ethernet */ 452 ifp->family = ARPHRD_ETHER; 453 break; 454 } 455 ifp->hwlen = sdl->sdl_alen; 456 memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen); 457#elif AF_PACKET 458 sll = (const void *)ifa->ifa_addr; 459 ifp->index = (unsigned int)sll->sll_ifindex; 460 ifp->family = sll->sll_hatype; 461 ifp->hwlen = sll->sll_halen; 462 if (ifp->hwlen != 0) 463 memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen); 464#endif 465 } 466#ifdef __linux__ 467 /* PPP addresses on Linux don't have hardware addresses */ 468 else 469 ifp->index = if_nametoindex(ifp->name); 470#endif 471 472 /* We only work on ethernet by default */ 473 if (ifp->family != ARPHRD_ETHER) { 474 if ((argc == 0 || argc == -1) && 475 ctx->ifac == 0 && !if_hasconf(ctx, ifp->name)) 476 active = IF_INACTIVE; 477 switch (ifp->family) { 478 case ARPHRD_IEEE1394: 479 case ARPHRD_INFINIBAND: 480#ifdef ARPHRD_LOOPBACK 481 case ARPHRD_LOOPBACK: 482#endif 483#ifdef ARPHRD_PPP 484 case ARPHRD_PPP: 485#endif 486 /* We don't warn for supported families */ 487 break; 488 489/* IFT already checked */ 490#ifndef AF_LINK 491 default: 492 if (active) 493 logwarnx("%s: unsupported" 494 " interface family %.2x", 495 ifp->name, ifp->family); 496 break; 497#endif 498 } 499 } 500 501 if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) { 502 /* Handle any platform init for the interface */ 503 if (active != IF_INACTIVE && if_init(ifp) == -1) { 504 logerr("%s: if_init", ifp->name); 505 if_free(ifp); 506 continue; 507 } 508 509 /* Ensure that the MTU is big enough for DHCP */ 510 if (if_getmtu(ifp) < MTU_MIN && active && 511 if_setmtu(ifp, MTU_MIN) == -1) 512 { 513 logerr("%s: if_setmtu", ifp->name); 514 if_free(ifp); 515 continue; 516 } 517 } 518 519#ifdef SIOCGIFPRIORITY 520 /* Respect the interface priority */ 521 memset(&ifr, 0, sizeof(ifr)); 522 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 523 if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0) 524 ifp->metric = (unsigned int)ifr.ifr_metric; 525 if_getssid(ifp); 526#else 527 /* We reserve the 100 range for virtual interfaces, if and when 528 * we can work them out. */ 529 ifp->metric = 200 + ifp->index; 530 if (if_getssid(ifp) != -1) { 531 ifp->wireless = 1; 532 ifp->metric += 100; 533 } 534#endif 535 536 ifp->active = active; 537 if (ifp->active) 538 ifp->carrier = if_carrier(ifp); 539 else 540 ifp->carrier = LINK_UNKNOWN; 541 TAILQ_INSERT_TAIL(ifs, ifp, next); 542 } 543 544 if_learnaddrs(ctx, ifs, ifaddrs); 545failed: 546 freeifaddrs(ifaddrs); 547 return ifs; 548} 549 550/* Decode bge0:1 as dev = bge, ppa = 0 and lun = 1 */ 551int 552if_nametospec(const char *ifname, struct if_spec *spec) 553{ 554 char *ep; 555 int e; 556 557 if (ifname == NULL || *ifname == '\0' || 558 strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >= 559 sizeof(spec->ifname) || 560 strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >= 561 sizeof(spec->drvname)) 562 { 563 errno = EINVAL; 564 return -1; 565 } 566 ep = strchr(spec->drvname, ':'); 567 if (ep) { 568 spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e); 569 if (e != 0) { 570 errno = e; 571 return -1; 572 } 573 *ep-- = '\0'; 574 } else { 575 spec->lun = -1; 576 ep = spec->drvname + strlen(spec->drvname) - 1; 577 } 578 strlcpy(spec->devname, spec->drvname, sizeof(spec->devname)); 579 while (ep > spec->drvname && isdigit((int)*ep)) 580 ep--; 581 if (*ep++ == ':') { 582 errno = EINVAL; 583 return -1; 584 } 585 spec->ppa = (int)strtoi(ep, NULL, 10, 0, INT_MAX, &e); 586 if (e != 0) 587 spec->ppa = -1; 588 *ep = '\0'; 589 590 return 0; 591} 592 593static struct interface * 594if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name) 595{ 596 597 if (ifaces != NULL) { 598 struct if_spec spec; 599 struct interface *ifp; 600 601 if (name && if_nametospec(name, &spec) == -1) 602 return NULL; 603 604 TAILQ_FOREACH(ifp, ifaces, next) { 605 if ((name && strcmp(ifp->name, spec.devname) == 0) || 606 (!name && ifp->index == idx)) 607 return ifp; 608 } 609 } 610 611 errno = ENXIO; 612 return NULL; 613} 614 615struct interface * 616if_find(struct if_head *ifaces, const char *name) 617{ 618 619 return if_findindexname(ifaces, 0, name); 620} 621 622struct interface * 623if_findindex(struct if_head *ifaces, unsigned int idx) 624{ 625 626 return if_findindexname(ifaces, idx, NULL); 627} 628 629struct interface * 630if_loopback(struct dhcpcd_ctx *ctx) 631{ 632 struct interface *ifp; 633 634 TAILQ_FOREACH(ifp, ctx->ifaces, next) { 635 if (ifp->flags & IFF_LOOPBACK) 636 return ifp; 637 } 638 return NULL; 639} 640 641int 642if_domtu(const struct interface *ifp, short int mtu) 643{ 644 int r; 645 struct ifreq ifr; 646 647 memset(&ifr, 0, sizeof(ifr)); 648 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 649 ifr.ifr_mtu = mtu; 650 r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr); 651 if (r == -1) 652 return -1; 653 return ifr.ifr_mtu; 654} 655 656/* Interface comparer for working out ordering. */ 657static int 658if_cmp(const struct interface *si, const struct interface *ti) 659{ 660#ifdef INET 661 int r; 662#endif 663 664 /* Check active first */ 665 if (si->active > ti->active) 666 return -1; 667 if (si->active < ti->active) 668 return 1; 669 670 /* Check carrier status next */ 671 if (si->carrier > ti->carrier) 672 return -1; 673 if (si->carrier < ti->carrier) 674 return 1; 675 676 if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti)) 677 return -1; 678 if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti)) 679 return 1; 680 if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti)) 681 return -1; 682 if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti)) 683 return 1; 684 if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti)) 685 return -1; 686 if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti)) 687 return 1; 688 689#ifdef INET 690 /* Special attention needed here due to states and IPv4LL. */ 691 if ((r = ipv4_ifcmp(si, ti)) != 0) 692 return r; 693#endif 694 695 /* Finally, metric */ 696 if (si->metric < ti->metric) 697 return -1; 698 if (si->metric > ti->metric) 699 return 1; 700 return 0; 701} 702 703/* Sort the interfaces into a preferred order - best first, worst last. */ 704void 705if_sortinterfaces(struct dhcpcd_ctx *ctx) 706{ 707 struct if_head sorted; 708 struct interface *ifp, *ift; 709 710 if (ctx->ifaces == NULL || 711 (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL || 712 TAILQ_NEXT(ifp, next) == NULL) 713 return; 714 715 TAILQ_INIT(&sorted); 716 TAILQ_REMOVE(ctx->ifaces, ifp, next); 717 TAILQ_INSERT_HEAD(&sorted, ifp, next); 718 while ((ifp = TAILQ_FIRST(ctx->ifaces))) { 719 TAILQ_REMOVE(ctx->ifaces, ifp, next); 720 TAILQ_FOREACH(ift, &sorted, next) { 721 if (if_cmp(ifp, ift) == -1) { 722 TAILQ_INSERT_BEFORE(ift, ifp, next); 723 break; 724 } 725 } 726 if (ift == NULL) 727 TAILQ_INSERT_TAIL(&sorted, ifp, next); 728 } 729 TAILQ_CONCAT(ctx->ifaces, &sorted, next); 730} 731 732int 733xsocket(int domain, int type, int protocol) 734{ 735 int s; 736#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK) 737 int xflags, xtype = type; 738#endif 739 740#ifndef HAVE_SOCK_CLOEXEC 741 if (xtype & SOCK_CLOEXEC) 742 type &= ~SOCK_CLOEXEC; 743#endif 744#ifndef HAVE_SOCK_NONBLOCK 745 if (xtype & SOCK_NONBLOCK) 746 type &= ~SOCK_NONBLOCK; 747#endif 748 749 if ((s = socket(domain, type, protocol)) == -1) 750 return -1; 751 752#ifndef HAVE_SOCK_CLOEXEC 753 if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 || 754 fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1)) 755 goto out; 756#endif 757#ifndef HAVE_SOCK_NONBLOCK 758 if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 || 759 fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1)) 760 goto out; 761#endif 762 763 return s; 764 765#if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK) 766out: 767 close(s); 768 return -1; 769#endif 770} 771