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