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