Import dhcpcd-8.0.4 to vendor branch.
[dragonfly.git] / contrib / dhcpcd / src / if.c
blobc483f046ff2e62feb9c1dc890de3e3171d4bda4c
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
5 * All rights reserved
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
34 #include "config.h"
36 #include <net/if.h>
37 #include <net/if_arp.h>
38 #include <netinet/in.h>
39 #ifdef AF_LINK
40 # include <net/if_dl.h>
41 # include <net/if_types.h>
42 # include <netinet/in_var.h>
43 # undef AF_PACKET /* Newer Illumos defines this */
44 #endif
45 #ifdef AF_PACKET
46 # include <netpacket/packet.h>
47 #endif
48 #ifdef SIOCGIFMEDIA
49 # include <net/if_media.h>
50 #endif
51 #include <net/route.h>
53 #include <ctype.h>
54 #include <errno.h>
55 #include <ifaddrs.h>
56 #include <inttypes.h>
57 #include <fnmatch.h>
58 #include <stddef.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
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"
75 #ifdef __sun
76 /* It has the ioctl, but the member is missing from the struct?
77 * No matter, our getifaddrs foo in if-sun.c will DTRT. */
78 #undef SIOCGIFHWADDR
79 #endif
81 void
82 if_free(struct interface *ifp)
85 if (ifp == NULL)
86 return;
87 #ifdef IPV4LL
88 ipv4ll_free(ifp);
89 #endif
90 #ifdef INET
91 dhcp_free(ifp);
92 ipv4_free(ifp);
93 #endif
94 #ifdef DHCP6
95 dhcp6_free(ifp);
96 #endif
97 #ifdef INET6
98 ipv6nd_free(ifp);
99 ipv6_free(ifp);
100 #endif
101 rt_freeif(ifp);
102 free_options(ifp->ctx, ifp->options);
103 free(ifp);
107 if_opensockets(struct dhcpcd_ctx *ctx)
110 if (if_opensockets_os(ctx) == -1)
111 return -1;
113 /* We use this socket for some operations without INET. */
114 ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
115 if (ctx->pf_inet_fd == -1)
116 return -1;
118 return 0;
121 void
122 if_closesockets(struct dhcpcd_ctx *ctx)
125 if (ctx->pf_inet_fd != -1)
126 close(ctx->pf_inet_fd);
128 if (ctx->priv) {
129 if_closesockets_os(ctx);
130 free(ctx->priv);
135 if_getflags(struct interface *ifp)
137 struct ifreq ifr = { .ifr_flags = 0 };
139 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
140 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
141 return -1;
142 ifp->flags = (unsigned int)ifr.ifr_flags;
143 return 0;
147 if_setflag(struct interface *ifp, short flag)
149 struct ifreq ifr = { .ifr_flags = 0 };
150 short f;
152 if (if_getflags(ifp) == -1)
153 return -1;
155 f = (short)ifp->flags;
156 if ((f & flag) == flag)
157 return 0;
159 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
160 ifr.ifr_flags = f | flag;
161 if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) == -1)
162 return -1;
164 ifp->flags = (unsigned int)ifr.ifr_flags;
165 return 0;
168 static int
169 if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
171 int i;
173 for (i = 0; i < ctx->ifcc; i++) {
174 if (strcmp(ctx->ifcv[i], ifname) == 0)
175 return 1;
177 return 0;
180 void
181 if_markaddrsstale(struct if_head *ifs)
183 struct interface *ifp;
185 TAILQ_FOREACH(ifp, ifs, next) {
186 #ifdef INET
187 ipv4_markaddrsstale(ifp);
188 #endif
189 #ifdef INET6
190 ipv6_markaddrsstale(ifp, 0);
191 #endif
195 void
196 if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs,
197 struct ifaddrs **ifaddrs)
199 struct ifaddrs *ifa;
200 struct interface *ifp;
201 #ifdef INET
202 const struct sockaddr_in *addr, *net, *brd;
203 #endif
204 #ifdef INET6
205 struct sockaddr_in6 *sin6, *net6;
206 #endif
207 int addrflags;
209 for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
210 if (ifa->ifa_addr == NULL)
211 continue;
212 if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
213 continue;
214 #ifdef HAVE_IFADDRS_ADDRFLAGS
215 addrflags = (int)ifa->ifa_addrflags;
216 #endif
217 switch(ifa->ifa_addr->sa_family) {
218 #ifdef INET
219 case AF_INET:
220 addr = (void *)ifa->ifa_addr;
221 net = (void *)ifa->ifa_netmask;
222 if (ifa->ifa_flags & IFF_POINTOPOINT)
223 brd = (void *)ifa->ifa_dstaddr;
224 else
225 brd = (void *)ifa->ifa_broadaddr;
226 #ifndef HAVE_IFADDRS_ADDRFLAGS
227 addrflags = if_addrflags(ifp, &addr->sin_addr,
228 ifa->ifa_name);
229 if (addrflags == -1) {
230 if (errno != EEXIST && errno != EADDRNOTAVAIL)
231 logerr("%s: if_addrflags", __func__);
232 continue;
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, 0);
238 break;
239 #endif
240 #ifdef INET6
241 case AF_INET6:
242 sin6 = (void *)ifa->ifa_addr;
243 net6 = (void *)ifa->ifa_netmask;
245 #ifdef __KAME__
246 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
247 /* Remove the scope from the address */
248 sin6->sin6_addr.s6_addr[2] =
249 sin6->sin6_addr.s6_addr[3] = '\0';
250 #endif
251 #ifndef HAVE_IFADDRS_ADDRFLAGS
252 addrflags = if_addrflags6(ifp, &sin6->sin6_addr,
253 ifa->ifa_name);
254 if (addrflags == -1) {
255 if (errno != EEXIST && errno != EADDRNOTAVAIL)
256 logerr("%s: if_addrflags6", __func__);
257 continue;
259 #endif
260 ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
261 ifa->ifa_name, &sin6->sin6_addr,
262 ipv6_prefixlen(&net6->sin6_addr), addrflags, 0);
263 break;
264 #endif
268 freeifaddrs(*ifaddrs);
269 *ifaddrs = NULL;
272 void
273 if_deletestaleaddrs(struct if_head *ifs)
275 struct interface *ifp;
277 TAILQ_FOREACH(ifp, ifs, next) {
278 #ifdef INET
279 ipv4_deletestaleaddrs(ifp);
280 #endif
281 #ifdef INET6
282 ipv6_deletestaleaddrs(ifp);
283 #endif
287 bool
288 if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen)
290 size_t i;
291 bool all_zeros, all_ones;
293 all_zeros = all_ones = true;
294 for (i = 0; i < hwlen; i++) {
295 if (hwaddr[i] != 0x00)
296 all_zeros = false;
297 if (hwaddr[i] != 0xff)
298 all_ones = false;
299 if (!all_zeros && !all_ones)
300 return true;
302 return false;
305 struct if_head *
306 if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
307 int argc, char * const *argv)
309 struct ifaddrs *ifa;
310 int i;
311 unsigned int active;
312 struct if_head *ifs;
313 struct interface *ifp;
314 struct if_spec spec;
315 #ifdef AF_LINK
316 const struct sockaddr_dl *sdl;
317 #ifdef IFLR_ACTIVE
318 struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
319 int link_fd;
320 #endif
321 #elif AF_PACKET
322 const struct sockaddr_ll *sll;
323 #endif
324 #if defined(SIOCGIFPRIORITY) || defined(SIOCGIFHWADDR)
325 struct ifreq ifr;
326 #endif
328 if ((ifs = malloc(sizeof(*ifs))) == NULL) {
329 logerr(__func__);
330 return NULL;
332 if (getifaddrs(ifaddrs) == -1) {
333 logerr(__func__);
334 free(ifs);
335 return NULL;
337 TAILQ_INIT(ifs);
339 #ifdef IFLR_ACTIVE
340 link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
341 if (link_fd == -1) {
342 logerr(__func__);
343 free(ifs);
344 return NULL;
346 #endif
348 for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
349 if (ifa->ifa_addr != NULL) {
350 #ifdef AF_LINK
351 if (ifa->ifa_addr->sa_family != AF_LINK)
352 continue;
353 #elif AF_PACKET
354 if (ifa->ifa_addr->sa_family != AF_PACKET)
355 continue;
356 #endif
358 if (if_nametospec(ifa->ifa_name, &spec) != 0)
359 continue;
361 /* It's possible for an interface to have >1 AF_LINK.
362 * For our purposes, we use the first one. */
363 TAILQ_FOREACH(ifp, ifs, next) {
364 if (strcmp(ifp->name, spec.devname) == 0)
365 break;
367 if (ifp)
368 continue;
370 if (argc > 0) {
371 for (i = 0; i < argc; i++) {
372 if (strcmp(argv[i], spec.devname) == 0)
373 break;
375 active = (i == argc) ? IF_INACTIVE : IF_ACTIVE_USER;
376 } else {
377 /* -1 means we're discovering against a specific
378 * interface, but we still need the below rules
379 * to apply. */
380 if (argc == -1 && strcmp(argv[0], spec.devname) != 0)
381 continue;
382 active = ctx->options & DHCPCD_INACTIVE ?
383 IF_INACTIVE: IF_ACTIVE_USER;
386 for (i = 0; i < ctx->ifdc; i++)
387 if (fnmatch(ctx->ifdv[i], spec.devname, 0) == 0)
388 break;
389 if (i < ctx->ifdc)
390 active = IF_INACTIVE;
391 for (i = 0; i < ctx->ifc; i++)
392 if (fnmatch(ctx->ifv[i], spec.devname, 0) == 0)
393 break;
394 if (ctx->ifc && i == ctx->ifc)
395 active = IF_INACTIVE;
396 for (i = 0; i < ctx->ifac; i++)
397 if (fnmatch(ctx->ifav[i], spec.devname, 0) == 0)
398 break;
399 if (ctx->ifac && i == ctx->ifac)
400 active = IF_INACTIVE;
402 #ifdef PLUGIN_DEV
403 /* Ensure that the interface name has settled */
404 if (!dev_initialized(ctx, spec.devname))
405 continue;
406 #endif
408 /* Don't allow loopback or pointopoint unless explicit */
409 if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) {
410 if ((argc == 0 || argc == -1) &&
411 ctx->ifac == 0 && !if_hasconf(ctx, spec.devname))
412 active = IF_INACTIVE;
415 if (if_vimaster(ctx, spec.devname) == 1) {
416 logfunc_t *logfunc = argc != 0 ? logerrx : logdebugx;
417 logfunc("%s: is a Virtual Interface Master, skipping",
418 spec.devname);
419 continue;
422 ifp = calloc(1, sizeof(*ifp));
423 if (ifp == NULL) {
424 logerr(__func__);
425 break;
427 ifp->ctx = ctx;
428 strlcpy(ifp->name, spec.devname, sizeof(ifp->name));
429 ifp->flags = ifa->ifa_flags;
431 if (ifa->ifa_addr != NULL) {
432 #ifdef AF_LINK
433 sdl = (const void *)ifa->ifa_addr;
435 #ifdef IFLR_ACTIVE
436 /* We need to check for active address */
437 strlcpy(iflr.iflr_name, ifp->name,
438 sizeof(iflr.iflr_name));
439 memcpy(&iflr.addr, ifa->ifa_addr,
440 MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
441 iflr.flags = IFLR_PREFIX;
442 iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
443 if (ioctl(link_fd, SIOCGLIFADDR, &iflr) == -1 ||
444 !(iflr.flags & IFLR_ACTIVE))
446 if_free(ifp);
447 continue;
449 #endif
451 ifp->index = sdl->sdl_index;
452 switch(sdl->sdl_type) {
453 #ifdef IFT_BRIDGE
454 case IFT_BRIDGE: /* FALLTHROUGH */
455 #endif
456 #ifdef IFT_PPP
457 case IFT_PPP: /* FALLTHROUGH */
458 #endif
459 #ifdef IFT_PROPVIRTUAL
460 case IFT_PROPVIRTUAL:
461 #endif
462 #if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL)
463 /* Don't allow unless explicit */
464 if ((argc == 0 || argc == -1) &&
465 ctx->ifac == 0 && active &&
466 !if_hasconf(ctx, ifp->name))
468 logdebugx("%s: ignoring due to"
469 " interface type and"
470 " no config",
471 ifp->name);
472 active = IF_INACTIVE;
474 __fallthrough; /* Appease gcc-7 */
475 /* FALLTHROUGH */
476 #endif
477 #ifdef IFT_L2VLAN
478 case IFT_L2VLAN: /* FALLTHROUGH */
479 #endif
480 #ifdef IFT_L3IPVLAN
481 case IFT_L3IPVLAN: /* FALLTHROUGH */
482 #endif
483 case IFT_ETHER:
484 ifp->family = ARPHRD_ETHER;
485 break;
486 #ifdef IFT_IEEE1394
487 case IFT_IEEE1394:
488 ifp->family = ARPHRD_IEEE1394;
489 break;
490 #endif
491 #ifdef IFT_INFINIBAND
492 case IFT_INFINIBAND:
493 ifp->family = ARPHRD_INFINIBAND;
494 break;
495 #endif
496 default:
497 /* Don't allow unless explicit */
498 if ((argc == 0 || argc == -1) &&
499 ctx->ifac == 0 &&
500 !if_hasconf(ctx, ifp->name))
501 active = IF_INACTIVE;
502 if (active)
503 logwarnx("%s: unsupported"
504 " interface type %.2x",
505 ifp->name, sdl->sdl_type);
506 /* Pretend it's ethernet */
507 ifp->family = ARPHRD_ETHER;
508 break;
510 ifp->hwlen = sdl->sdl_alen;
511 memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
512 #elif AF_PACKET
513 sll = (const void *)ifa->ifa_addr;
514 ifp->index = (unsigned int)sll->sll_ifindex;
515 ifp->family = sll->sll_hatype;
516 ifp->hwlen = sll->sll_halen;
517 if (ifp->hwlen != 0)
518 memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
519 #endif
521 #ifdef SIOCGIFHWADDR
522 else {
523 /* This is a huge bug in getifaddrs(3) as there
524 * is no reason why this can't be returned in
525 * ifa_addr. */
526 memset(&ifr, 0, sizeof(ifr));
527 strlcpy(ifr.ifr_name, ifa->ifa_name,
528 sizeof(ifr.ifr_name));
529 if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
530 logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
531 ifp->family = ifr.ifr_hwaddr.sa_family;
532 if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
533 logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
534 ifp->index = (unsigned int)ifr.ifr_ifindex;
536 #endif
538 /* Ensure hardware address is valid. */
539 if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen))
540 ifp->hwlen = 0;
542 /* We only work on ethernet by default */
543 if (ifp->family != ARPHRD_ETHER) {
544 if ((argc == 0 || argc == -1) &&
545 ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
546 active = IF_INACTIVE;
547 switch (ifp->family) {
548 case ARPHRD_IEEE1394:
549 case ARPHRD_INFINIBAND:
550 #ifdef ARPHRD_LOOPBACK
551 case ARPHRD_LOOPBACK:
552 #endif
553 #ifdef ARPHRD_PPP
554 case ARPHRD_PPP:
555 #endif
556 #ifdef ARPHRD_NONE
557 case ARPHRD_NONE:
558 #endif
559 /* We don't warn for supported families */
560 break;
562 /* IFT already checked */
563 #ifndef AF_LINK
564 default:
565 if (active)
566 logwarnx("%s: unsupported"
567 " interface family %.2x",
568 ifp->name, ifp->family);
569 break;
570 #endif
574 if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
575 /* Handle any platform init for the interface */
576 if (active != IF_INACTIVE && if_init(ifp) == -1) {
577 logerr("%s: if_init", ifp->name);
578 if_free(ifp);
579 continue;
583 ifp->vlanid = if_vlanid(ifp);
585 #ifdef SIOCGIFPRIORITY
586 /* Respect the interface priority */
587 memset(&ifr, 0, sizeof(ifr));
588 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
589 if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
590 ifp->metric = (unsigned int)ifr.ifr_metric;
591 if_getssid(ifp);
592 #else
593 /* We reserve the 100 range for virtual interfaces, if and when
594 * we can work them out. */
595 ifp->metric = 200 + ifp->index;
596 if (if_getssid(ifp) != -1) {
597 ifp->wireless = true;
598 ifp->metric += 100;
600 #endif
602 ifp->active = active;
603 if (ifp->active)
604 ifp->carrier = if_carrier(ifp);
605 else
606 ifp->carrier = LINK_UNKNOWN;
607 TAILQ_INSERT_TAIL(ifs, ifp, next);
610 #ifdef IFLR_ACTIVE
611 close(link_fd);
612 #endif
613 return ifs;
616 /* Decode bge0:1 as dev = bge, ppa = 0 and lun = 1 */
618 if_nametospec(const char *ifname, struct if_spec *spec)
620 char *ep;
621 int e;
623 if (ifname == NULL || *ifname == '\0' ||
624 strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >=
625 sizeof(spec->ifname) ||
626 strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >=
627 sizeof(spec->drvname))
629 errno = EINVAL;
630 return -1;
632 ep = strchr(spec->drvname, ':');
633 if (ep) {
634 spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e);
635 if (e != 0) {
636 errno = e;
637 return -1;
639 *ep-- = '\0';
640 } else {
641 spec->lun = -1;
642 ep = spec->drvname + strlen(spec->drvname) - 1;
644 strlcpy(spec->devname, spec->drvname, sizeof(spec->devname));
645 while (ep > spec->drvname && isdigit((int)*ep))
646 ep--;
647 if (*ep++ == ':') {
648 errno = EINVAL;
649 return -1;
651 spec->ppa = (int)strtoi(ep, NULL, 10, 0, INT_MAX, &e);
652 if (e != 0)
653 spec->ppa = -1;
654 *ep = '\0';
656 return 0;
659 static struct interface *
660 if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
663 if (ifaces != NULL) {
664 struct if_spec spec;
665 struct interface *ifp;
667 if (name && if_nametospec(name, &spec) == -1)
668 return NULL;
670 TAILQ_FOREACH(ifp, ifaces, next) {
671 if ((name && strcmp(ifp->name, spec.devname) == 0) ||
672 (!name && ifp->index == idx))
673 return ifp;
677 errno = ENXIO;
678 return NULL;
681 struct interface *
682 if_find(struct if_head *ifaces, const char *name)
685 return if_findindexname(ifaces, 0, name);
688 struct interface *
689 if_findindex(struct if_head *ifaces, unsigned int idx)
692 return if_findindexname(ifaces, idx, NULL);
695 struct interface *
696 if_loopback(struct dhcpcd_ctx *ctx)
698 struct interface *ifp;
700 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
701 if (ifp->flags & IFF_LOOPBACK)
702 return ifp;
704 return NULL;
708 if_domtu(const struct interface *ifp, short int mtu)
710 int r;
711 struct ifreq ifr;
713 #ifdef __sun
714 if (mtu == 0)
715 return if_mtu_os(ifp);
716 #endif
718 memset(&ifr, 0, sizeof(ifr));
719 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
720 ifr.ifr_mtu = mtu;
721 r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
722 if (r == -1)
723 return -1;
724 return ifr.ifr_mtu;
727 #ifdef ALIAS_ADDR
729 if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
732 if (lun == 0)
733 return strlcpy(alias, ifname, alias_len);
734 return snprintf(alias, alias_len, "%s:%u", ifname, lun);
736 #endif
738 struct interface *
739 if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
741 struct cmsghdr *cm;
742 unsigned int ifindex = 0;
743 struct interface *ifp;
744 #if defined(INET) && defined(IP_PKTINFO)
745 struct in_pktinfo ipi;
746 #endif
747 #ifdef INET6
748 struct in6_pktinfo ipi6;
749 #else
750 UNUSED(hoplimit);
751 #endif
753 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
755 cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
757 #if defined(INET) && defined(IP_PKTINFO)
758 if (cm->cmsg_level == IPPROTO_IP) {
759 switch(cm->cmsg_type) {
760 case IP_PKTINFO:
761 if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
762 continue;
763 memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
764 ifindex = (unsigned int)ipi.ipi_ifindex;
765 break;
768 #endif
769 #ifdef INET6
770 if (cm->cmsg_level == IPPROTO_IPV6) {
771 switch(cm->cmsg_type) {
772 case IPV6_PKTINFO:
773 if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
774 continue;
775 memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
776 ifindex = (unsigned int)ipi6.ipi6_ifindex;
777 break;
778 case IPV6_HOPLIMIT:
779 if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
780 continue;
781 if (hoplimit == NULL)
782 break;
783 memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
784 break;
787 #endif
790 /* Find the receiving interface */
791 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
792 if (ifp->index == ifindex)
793 break;
795 if (ifp == NULL)
796 errno = ESRCH;
797 return ifp;
801 xsocket(int domain, int type, int protocol)
803 int s;
804 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
805 int xflags, xtype = type;
806 #endif
807 #ifdef SO_RERROR
808 int on;
809 #endif
811 #ifndef HAVE_SOCK_CLOEXEC
812 if (xtype & SOCK_CLOEXEC)
813 type &= ~SOCK_CLOEXEC;
814 #endif
815 #ifndef HAVE_SOCK_NONBLOCK
816 if (xtype & SOCK_NONBLOCK)
817 type &= ~SOCK_NONBLOCK;
818 #endif
820 if ((s = socket(domain, type, protocol)) == -1)
821 return -1;
823 #ifndef HAVE_SOCK_CLOEXEC
824 if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
825 fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1))
826 goto out;
827 #endif
828 #ifndef HAVE_SOCK_NONBLOCK
829 if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 ||
830 fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1))
831 goto out;
832 #endif
834 #ifdef SO_RERROR
835 /* Tell recvmsg(2) to return ENOBUFS if the receiving socket overflows. */
836 on = 1;
837 if (setsockopt(s, SOL_SOCKET, SO_RERROR, &on, sizeof(on)) == -1)
838 logerr("%s: SO_RERROR", __func__);
839 #endif
841 return s;
843 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
844 out:
845 close(s);
846 return -1;
847 #endif