1 /*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2015 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 <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
split_interface_lease(const char * ifname,int * interface_name_len,const char ** lease_identifier)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
if_free(struct interface * ifp)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
if_carrier(struct interface * iface)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
if_setflag(struct interface * ifp,short flag)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
if_hasconf(struct dhcpcd_ctx * ctx,const char * ifname)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
if_learnaddrs1(struct dhcpcd_ctx * ctx,struct if_head * ifs,struct ifaddrs * ifaddrs)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 *
if_discover(struct dhcpcd_ctx * ctx,int argc,char * const * argv)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 *
if_findindexname(struct if_head * ifaces,unsigned int idx,const char * name)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 *
if_find(struct if_head * ifaces,const char * name)614 if_find(struct if_head *ifaces, const char *name)
615 {
616
617 return if_findindexname(ifaces, 0, name);
618 }
619
620 struct interface *
if_findindex(struct if_head * ifaces,unsigned int idx)621 if_findindex(struct if_head *ifaces, unsigned int idx)
622 {
623
624 return if_findindexname(ifaces, idx, NULL);
625 }
626
627 int
if_domtu(const char * ifname,short int mtu)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
if_cmp(const struct interface * si,const struct interface * ti)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
if_sortinterfaces(struct dhcpcd_ctx * ctx)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