Update to dhcpcd-9.3.0 with the following changes:
[dragonfly.git] / contrib / dhcpcd / src / if.c
blob24d1f26665f293587e6e20d4a617e3ea36eef2b0
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2020 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 <fcntl.h> /* Needs to be here for old Linux */
36 #include "config.h"
38 #include <net/if.h>
39 #include <net/if_arp.h>
40 #include <netinet/in.h>
41 #ifdef AF_LINK
42 # include <net/if_dl.h>
43 # include <net/if_types.h>
44 # include <netinet/in_var.h>
45 # undef AF_PACKET /* Newer Illumos defines this */
46 #endif
47 #ifdef AF_PACKET
48 # include <netpacket/packet.h>
49 #endif
50 #ifdef SIOCGIFMEDIA
51 # include <net/if_media.h>
52 #endif
53 #include <net/route.h>
55 #include <ctype.h>
56 #include <errno.h>
57 #include <ifaddrs.h>
58 #include <inttypes.h>
59 #include <fnmatch.h>
60 #include <stddef.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <syslog.h>
65 #include <unistd.h>
67 #define ELOOP_QUEUE ELOOP_IF
68 #include "common.h"
69 #include "eloop.h"
70 #include "dev.h"
71 #include "dhcp.h"
72 #include "dhcp6.h"
73 #include "if.h"
74 #include "if-options.h"
75 #include "ipv4.h"
76 #include "ipv4ll.h"
77 #include "ipv6nd.h"
78 #include "logerr.h"
79 #include "privsep.h"
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 #ifdef IFLR_ACTIVE
114 ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
115 if (ctx->pf_link_fd == -1)
116 return -1;
117 #ifdef HAVE_CAPSICUM
118 if (ps_rights_limit_ioctl(ctx->pf_link_fd) == -1)
119 return -1;
120 #endif
121 #endif
123 /* We use this socket for some operations without INET. */
124 ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
125 if (ctx->pf_inet_fd == -1)
126 return -1;
128 return 0;
131 void
132 if_closesockets(struct dhcpcd_ctx *ctx)
135 if (ctx->pf_inet_fd != -1)
136 close(ctx->pf_inet_fd);
137 #ifdef PF_LINK
138 if (ctx->pf_link_fd != -1)
139 close(ctx->pf_link_fd);
140 #endif
142 if (ctx->priv) {
143 if_closesockets_os(ctx);
144 free(ctx->priv);
149 if_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, size_t len)
152 #ifdef PRIVSEP
153 if (ctx->options & DHCPCD_PRIVSEP)
154 return (int)ps_root_ioctl(ctx, req, data, len);
155 #endif
156 return ioctl(ctx->pf_inet_fd, req, data, len);
160 if_getflags(struct interface *ifp)
162 struct ifreq ifr = { .ifr_flags = 0 };
164 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
165 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
166 return -1;
167 ifp->flags = (unsigned int)ifr.ifr_flags;
168 return 0;
172 if_setflag(struct interface *ifp, short setflag, short unsetflag)
174 struct ifreq ifr = { .ifr_flags = 0 };
175 short oflags;
177 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
178 if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
179 return -1;
181 oflags = ifr.ifr_flags;
182 ifr.ifr_flags |= setflag;
183 ifr.ifr_flags &= (short)~unsetflag;
184 if (ifr.ifr_flags != oflags &&
185 if_ioctl(ifp->ctx, SIOCSIFFLAGS, &ifr, sizeof(ifr)) == -1)
186 return -1;
189 * Do NOT set ifp->flags here.
190 * We need to listen for flag updates from the kernel as they
191 * need to sync with carrier.
193 return 0;
197 if_randomisemac(struct interface *ifp)
199 uint32_t randnum;
200 size_t hwlen = ifp->hwlen, rlen = 0;
201 uint8_t buf[HWADDR_LEN], *bp = buf, *rp = (uint8_t *)&randnum;
202 char sbuf[HWADDR_LEN * 3];
203 int retval;
205 if (hwlen == 0) {
206 errno = ENOTSUP;
207 return -1;
209 if (hwlen > sizeof(buf)) {
210 errno = ENOBUFS;
211 return -1;
214 for (; hwlen != 0; hwlen--) {
215 if (rlen == 0) {
216 randnum = arc4random();
217 rp = (uint8_t *)&randnum;
218 rlen = sizeof(randnum);
220 *bp++ = *rp++;
221 rlen--;
224 /* Unicast address and locally administered. */
225 buf[0] &= 0xFC;
226 buf[0] |= 0x02;
228 logdebugx("%s: hardware address randomised to %s",
229 ifp->name,
230 hwaddr_ntoa(buf, ifp->hwlen, sbuf, sizeof(sbuf)));
231 retval = if_setmac(ifp, buf, ifp->hwlen);
232 if (retval == 0)
233 memcpy(ifp->hwaddr, buf, ifp->hwlen);
234 return retval;
237 static int
238 if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
240 int i;
242 for (i = 0; i < ctx->ifcc; i++) {
243 if (strcmp(ctx->ifcv[i], ifname) == 0)
244 return 1;
246 return 0;
249 void
250 if_markaddrsstale(struct if_head *ifs)
252 struct interface *ifp;
254 TAILQ_FOREACH(ifp, ifs, next) {
255 #ifdef INET
256 ipv4_markaddrsstale(ifp);
257 #endif
258 #ifdef INET6
259 ipv6_markaddrsstale(ifp, 0);
260 #endif
264 void
265 if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs,
266 struct ifaddrs **ifaddrs)
268 struct ifaddrs *ifa;
269 struct interface *ifp;
270 #ifdef INET
271 const struct sockaddr_in *addr, *net, *brd;
272 #endif
273 #ifdef INET6
274 struct sockaddr_in6 *sin6, *net6;
275 #endif
276 int addrflags;
278 for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
279 if (ifa->ifa_addr == NULL)
280 continue;
281 if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
282 continue;
283 #ifdef HAVE_IFADDRS_ADDRFLAGS
284 addrflags = (int)ifa->ifa_addrflags;
285 #endif
286 switch(ifa->ifa_addr->sa_family) {
287 #ifdef INET
288 case AF_INET:
289 addr = (void *)ifa->ifa_addr;
290 net = (void *)ifa->ifa_netmask;
291 if (ifa->ifa_flags & IFF_POINTOPOINT)
292 brd = (void *)ifa->ifa_dstaddr;
293 else
294 brd = (void *)ifa->ifa_broadaddr;
295 #ifndef HAVE_IFADDRS_ADDRFLAGS
296 addrflags = if_addrflags(ifp, &addr->sin_addr,
297 ifa->ifa_name);
298 if (addrflags == -1) {
299 if (errno != EEXIST && errno != EADDRNOTAVAIL) {
300 char dbuf[INET_ADDRSTRLEN];
301 const char *dbp;
303 dbp = inet_ntop(AF_INET, &addr->sin_addr,
304 dbuf, sizeof(dbuf));
305 logerr("%s: if_addrflags: %s%%%s",
306 __func__, dbp, ifp->name);
308 continue;
310 #endif
311 ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
312 &addr->sin_addr, &net->sin_addr,
313 brd ? &brd->sin_addr : NULL, addrflags, 0);
314 break;
315 #endif
316 #ifdef INET6
317 case AF_INET6:
318 sin6 = (void *)ifa->ifa_addr;
319 net6 = (void *)ifa->ifa_netmask;
321 #ifdef __KAME__
322 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
323 /* Remove the scope from the address */
324 sin6->sin6_addr.s6_addr[2] =
325 sin6->sin6_addr.s6_addr[3] = '\0';
326 #endif
327 #ifndef HAVE_IFADDRS_ADDRFLAGS
328 addrflags = if_addrflags6(ifp, &sin6->sin6_addr,
329 ifa->ifa_name);
330 if (addrflags == -1) {
331 if (errno != EEXIST && errno != EADDRNOTAVAIL) {
332 char dbuf[INET6_ADDRSTRLEN];
333 const char *dbp;
335 dbp = inet_ntop(AF_INET6, &sin6->sin6_addr,
336 dbuf, sizeof(dbuf));
337 logerr("%s: if_addrflags6: %s%%%s",
338 __func__, dbp, ifp->name);
340 continue;
342 #endif
343 ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
344 ifa->ifa_name, &sin6->sin6_addr,
345 ipv6_prefixlen(&net6->sin6_addr), addrflags, 0);
346 break;
347 #endif
351 #ifdef PRIVSEP_GETIFADDRS
352 if (IN_PRIVSEP(ctx))
353 free(*ifaddrs);
354 else
355 #endif
356 freeifaddrs(*ifaddrs);
357 *ifaddrs = NULL;
360 void
361 if_deletestaleaddrs(struct if_head *ifs)
363 struct interface *ifp;
365 TAILQ_FOREACH(ifp, ifs, next) {
366 #ifdef INET
367 ipv4_deletestaleaddrs(ifp);
368 #endif
369 #ifdef INET6
370 ipv6_deletestaleaddrs(ifp);
371 #endif
375 bool
376 if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen)
378 size_t i;
379 bool all_zeros, all_ones;
381 all_zeros = all_ones = true;
382 for (i = 0; i < hwlen; i++) {
383 if (hwaddr[i] != 0x00)
384 all_zeros = false;
385 if (hwaddr[i] != 0xff)
386 all_ones = false;
387 if (!all_zeros && !all_ones)
388 return true;
390 return false;
393 #if defined(AF_PACKET) && !defined(AF_LINK)
394 static unsigned int
395 if_check_arphrd(struct interface *ifp, unsigned int active, bool if_noconf)
398 switch(ifp->hwtype) {
399 case ARPHRD_ETHER: /* FALLTHROUGH */
400 case ARPHRD_IEEE1394: /* FALLTHROUGH */
401 case ARPHRD_INFINIBAND: /* FALLTHROUGH */
402 case ARPHRD_NONE: /* FALLTHROUGH */
403 break;
404 case ARPHRD_LOOPBACK:
405 case ARPHRD_PPP:
406 if (if_noconf && active) {
407 logdebugx("%s: ignoring due to interface type and"
408 " no config",
409 ifp->name);
410 active = IF_INACTIVE;
412 break;
413 default:
414 if (if_noconf)
415 active = IF_INACTIVE;
416 if (active)
417 logwarnx("%s: unsupported interface type 0x%.2x",
418 ifp->name, ifp->hwtype);
419 break;
422 return active;
424 #endif
426 struct if_head *
427 if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
428 int argc, char * const *argv)
430 struct ifaddrs *ifa;
431 int i;
432 unsigned int active;
433 struct if_head *ifs;
434 struct interface *ifp;
435 struct if_spec spec;
436 bool if_noconf;
437 #ifdef AF_LINK
438 const struct sockaddr_dl *sdl;
439 #ifdef IFLR_ACTIVE
440 struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
441 #endif
442 #elif defined(AF_PACKET)
443 const struct sockaddr_ll *sll;
444 #endif
445 #if defined(SIOCGIFPRIORITY)
446 struct ifreq ifr;
447 #endif
449 if ((ifs = malloc(sizeof(*ifs))) == NULL) {
450 logerr(__func__);
451 return NULL;
453 TAILQ_INIT(ifs);
455 #ifdef PRIVSEP_GETIFADDRS
456 if (ctx->options & DHCPCD_PRIVSEP) {
457 if (ps_root_getifaddrs(ctx, ifaddrs) == -1) {
458 logerr("ps_root_getifaddrs");
459 free(ifs);
460 return NULL;
462 } else
463 #endif
464 if (getifaddrs(ifaddrs) == -1) {
465 logerr("getifaddrs");
466 free(ifs);
467 return NULL;
470 for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
471 if (ifa->ifa_addr != NULL) {
472 #ifdef AF_LINK
473 if (ifa->ifa_addr->sa_family != AF_LINK)
474 continue;
475 #elif defined(AF_PACKET)
476 if (ifa->ifa_addr->sa_family != AF_PACKET)
477 continue;
478 #endif
480 if (if_nametospec(ifa->ifa_name, &spec) != 0)
481 continue;
483 /* It's possible for an interface to have >1 AF_LINK.
484 * For our purposes, we use the first one. */
485 TAILQ_FOREACH(ifp, ifs, next) {
486 if (strcmp(ifp->name, spec.devname) == 0)
487 break;
489 if (ifp)
490 continue;
492 if (argc > 0) {
493 for (i = 0; i < argc; i++) {
494 if (strcmp(argv[i], spec.devname) == 0)
495 break;
497 active = (i == argc) ? IF_INACTIVE : IF_ACTIVE_USER;
498 } else {
499 /* -1 means we're discovering against a specific
500 * interface, but we still need the below rules
501 * to apply. */
502 if (argc == -1 && strcmp(argv[0], spec.devname) != 0)
503 continue;
504 active = ctx->options & DHCPCD_INACTIVE ?
505 IF_INACTIVE: IF_ACTIVE_USER;
508 for (i = 0; i < ctx->ifdc; i++)
509 if (fnmatch(ctx->ifdv[i], spec.devname, 0) == 0)
510 break;
511 if (i < ctx->ifdc)
512 active = IF_INACTIVE;
513 for (i = 0; i < ctx->ifc; i++)
514 if (fnmatch(ctx->ifv[i], spec.devname, 0) == 0)
515 break;
516 if (ctx->ifc && i == ctx->ifc)
517 active = IF_INACTIVE;
518 for (i = 0; i < ctx->ifac; i++)
519 if (fnmatch(ctx->ifav[i], spec.devname, 0) == 0)
520 break;
521 if (ctx->ifac && i == ctx->ifac)
522 active = IF_INACTIVE;
524 #ifdef PLUGIN_DEV
525 /* Ensure that the interface name has settled */
526 if (!dev_initialised(ctx, spec.devname)) {
527 logdebugx("%s: waiting for interface to initialise",
528 spec.devname);
529 continue;
531 #endif
533 if (if_vimaster(ctx, spec.devname) == 1) {
534 int loglevel = argc != 0 ? LOG_ERR : LOG_DEBUG;
535 logmessage(loglevel,
536 "%s: is a Virtual Interface Master, skipping",
537 spec.devname);
538 continue;
541 if_noconf = ((argc == 0 || argc == -1) && ctx->ifac == 0 &&
542 !if_hasconf(ctx, spec.devname));
544 /* Don't allow some reserved interface names unless explicit. */
545 if (if_noconf && if_ignore(ctx, spec.devname)) {
546 logdebugx("%s: ignoring due to interface type and"
547 " no config", spec.devname);
548 active = IF_INACTIVE;
551 ifp = calloc(1, sizeof(*ifp));
552 if (ifp == NULL) {
553 logerr(__func__);
554 break;
556 ifp->ctx = ctx;
557 strlcpy(ifp->name, spec.devname, sizeof(ifp->name));
558 ifp->flags = ifa->ifa_flags;
560 if (ifa->ifa_addr != NULL) {
561 #ifdef AF_LINK
562 sdl = (const void *)ifa->ifa_addr;
564 #ifdef IFLR_ACTIVE
565 /* We need to check for active address */
566 strlcpy(iflr.iflr_name, ifp->name,
567 sizeof(iflr.iflr_name));
568 memcpy(&iflr.addr, ifa->ifa_addr,
569 MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
570 iflr.flags = IFLR_PREFIX;
571 iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
572 if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 ||
573 !(iflr.flags & IFLR_ACTIVE))
575 if_free(ifp);
576 continue;
578 #endif
580 ifp->index = sdl->sdl_index;
581 switch(sdl->sdl_type) {
582 #ifdef IFT_BRIDGE
583 case IFT_BRIDGE: /* FALLTHROUGH */
584 #endif
585 #ifdef IFT_PROPVIRTUAL
586 case IFT_PROPVIRTUAL: /* FALLTHROUGH */
587 #endif
588 #ifdef IFT_TUNNEL
589 case IFT_TUNNEL: /* FALLTHROUGH */
590 #endif
591 case IFT_LOOP: /* FALLTHROUGH */
592 case IFT_PPP:
593 /* Don't allow unless explicit */
594 if (if_noconf && active) {
595 logdebugx("%s: ignoring due to"
596 " interface type and"
597 " no config",
598 ifp->name);
599 active = IF_INACTIVE;
601 __fallthrough; /* appease gcc */
602 /* FALLTHROUGH */
603 #ifdef IFT_L2VLAN
604 case IFT_L2VLAN: /* FALLTHROUGH */
605 #endif
606 #ifdef IFT_L3IPVLAN
607 case IFT_L3IPVLAN: /* FALLTHROUGH */
608 #endif
609 case IFT_ETHER:
610 ifp->hwtype = ARPHRD_ETHER;
611 break;
612 #ifdef IFT_IEEE1394
613 case IFT_IEEE1394:
614 ifp->hwtype = ARPHRD_IEEE1394;
615 break;
616 #endif
617 #ifdef IFT_INFINIBAND
618 case IFT_INFINIBAND:
619 ifp->hwtype = ARPHRD_INFINIBAND;
620 break;
621 #endif
622 default:
623 /* Don't allow unless explicit */
624 if (if_noconf)
625 active = IF_INACTIVE;
626 if (active)
627 logwarnx("%s: unsupported"
628 " interface type 0x%.2x",
629 ifp->name, sdl->sdl_type);
630 /* Pretend it's ethernet */
631 ifp->hwtype = ARPHRD_ETHER;
632 break;
634 ifp->hwlen = sdl->sdl_alen;
635 memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
636 #elif defined(AF_PACKET)
637 sll = (const void *)ifa->ifa_addr;
638 ifp->index = (unsigned int)sll->sll_ifindex;
639 ifp->hwtype = sll->sll_hatype;
640 ifp->hwlen = sll->sll_halen;
641 if (ifp->hwlen != 0)
642 memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
643 active = if_check_arphrd(ifp, active, if_noconf);
644 #endif
646 #ifdef __linux__
647 else {
648 struct ifreq ifr = { .ifr_flags = 0 };
650 /* This is a huge bug in getifaddrs(3) as there
651 * is no reason why this can't be returned in
652 * ifa_addr. */
653 strlcpy(ifr.ifr_name, ifa->ifa_name,
654 sizeof(ifr.ifr_name));
655 if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
656 logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
657 ifp->hwtype = ifr.ifr_hwaddr.sa_family;
658 if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
659 logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
660 ifp->index = (unsigned int)ifr.ifr_ifindex;
661 if_check_arphrd(ifp, active, if_noconf);
663 #endif
665 if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
666 /* Handle any platform init for the interface */
667 if (active != IF_INACTIVE && if_init(ifp) == -1) {
668 logerr("%s: if_init", ifp->name);
669 if_free(ifp);
670 continue;
674 ifp->vlanid = if_vlanid(ifp);
676 #ifdef SIOCGIFPRIORITY
677 /* Respect the interface priority */
678 memset(&ifr, 0, sizeof(ifr));
679 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
680 if (pioctl(ctx, SIOCGIFPRIORITY, &ifr, sizeof(ifr)) == 0)
681 ifp->metric = (unsigned int)ifr.ifr_metric;
682 if_getssid(ifp);
683 #else
684 /* We reserve the 100 range for virtual interfaces, if and when
685 * we can work them out. */
686 ifp->metric = 200 + ifp->index;
687 if (if_getssid(ifp) != -1) {
688 ifp->wireless = true;
689 ifp->metric += 100;
691 #endif
693 ifp->active = active;
694 ifp->carrier = if_carrier(ifp, ifa->ifa_data);
695 TAILQ_INSERT_TAIL(ifs, ifp, next);
698 return ifs;
702 * eth0.100:2 OR eth0i100:2 (seems to be NetBSD xvif(4) only)
704 * drvname == eth
705 * devname == eth0.100 OR eth0i100
706 * ppa = 0
707 * lun = 2
710 if_nametospec(const char *ifname, struct if_spec *spec)
712 char *ep, *pp;
713 int e;
715 if (ifname == NULL || *ifname == '\0' ||
716 strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >=
717 sizeof(spec->ifname) ||
718 strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >=
719 sizeof(spec->drvname))
721 errno = EINVAL;
722 return -1;
725 /* :N is an alias */
726 ep = strchr(spec->drvname, ':');
727 if (ep) {
728 spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e);
729 if (e != 0) {
730 errno = e;
731 return -1;
733 *ep = '\0';
734 #ifdef __sun
735 ep--;
736 #endif
737 } else {
738 spec->lun = -1;
739 #ifdef __sun
740 ep = spec->drvname + strlen(spec->drvname) - 1;
741 #endif
744 strlcpy(spec->devname, spec->drvname, sizeof(spec->devname));
745 #ifdef __sun
746 /* Solaris has numbers in the driver name, such as e1000g */
747 while (ep > spec->drvname && isdigit((int)*ep))
748 ep--;
749 if (*ep++ == ':') {
750 errno = EINVAL;
751 return -1;
753 #else
754 /* BSD and Linux no not have numbers in the driver name */
755 for (ep = spec->drvname; *ep != '\0' && !isdigit((int)*ep); ep++) {
756 if (*ep == ':') {
757 errno = EINVAL;
758 return -1;
761 #endif
762 spec->ppa = (int)strtoi(ep, &pp, 10, 0, INT_MAX, &e);
763 *ep = '\0';
765 #ifndef __sun
767 * . is used for VLAN style names
768 * i is used on NetBSD for xvif interfaces
770 if (pp != NULL && (*pp == '.' || *pp == 'i')) {
771 spec->vlid = (int)strtoi(pp + 1, NULL, 10, 0, INT_MAX, &e);
772 if (e)
773 spec->vlid = -1;
774 } else
775 #endif
776 spec->vlid = -1;
778 return 0;
781 static struct interface *
782 if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
785 if (ifaces != NULL) {
786 struct if_spec spec;
787 struct interface *ifp;
789 if (name && if_nametospec(name, &spec) == -1)
790 return NULL;
792 TAILQ_FOREACH(ifp, ifaces, next) {
793 if ((name && strcmp(ifp->name, spec.devname) == 0) ||
794 (!name && ifp->index == idx))
795 return ifp;
799 errno = ENXIO;
800 return NULL;
803 struct interface *
804 if_find(struct if_head *ifaces, const char *name)
807 return if_findindexname(ifaces, 0, name);
810 struct interface *
811 if_findindex(struct if_head *ifaces, unsigned int idx)
814 return if_findindexname(ifaces, idx, NULL);
817 struct interface *
818 if_loopback(struct dhcpcd_ctx *ctx)
820 struct interface *ifp;
822 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
823 if (ifp->flags & IFF_LOOPBACK)
824 return ifp;
826 return NULL;
830 if_domtu(const struct interface *ifp, short int mtu)
832 int r;
833 struct ifreq ifr;
835 #ifdef __sun
836 if (mtu == 0)
837 return if_mtu_os(ifp);
838 #endif
840 memset(&ifr, 0, sizeof(ifr));
841 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
842 ifr.ifr_mtu = mtu;
843 if (mtu != 0)
844 r = if_ioctl(ifp->ctx, SIOCSIFMTU, &ifr, sizeof(ifr));
845 else
846 r = pioctl(ifp->ctx, SIOCGIFMTU, &ifr, sizeof(ifr));
848 if (r == -1)
849 return -1;
850 return ifr.ifr_mtu;
853 #ifdef ALIAS_ADDR
855 if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
858 if (lun == 0)
859 return strlcpy(alias, ifname, alias_len);
860 return snprintf(alias, alias_len, "%s:%u", ifname, lun);
862 #endif
864 struct interface *
865 if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
867 struct cmsghdr *cm;
868 unsigned int ifindex = 0;
869 struct interface *ifp;
870 #ifdef INET
871 #ifdef IP_RECVIF
872 struct sockaddr_dl sdl;
873 #else
874 struct in_pktinfo ipi;
875 #endif
876 #endif
877 #ifdef INET6
878 struct in6_pktinfo ipi6;
879 #else
880 UNUSED(hoplimit);
881 #endif
883 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
885 cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
887 #ifdef INET
888 if (cm->cmsg_level == IPPROTO_IP) {
889 switch(cm->cmsg_type) {
890 #ifdef IP_RECVIF
891 case IP_RECVIF:
892 if (cm->cmsg_len <
893 offsetof(struct sockaddr_dl, sdl_index) +
894 sizeof(sdl.sdl_index))
895 continue;
896 memcpy(&sdl, CMSG_DATA(cm),
897 MIN(sizeof(sdl), cm->cmsg_len));
898 ifindex = sdl.sdl_index;
899 break;
900 #else
901 case IP_PKTINFO:
902 if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
903 continue;
904 memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
905 ifindex = (unsigned int)ipi.ipi_ifindex;
906 break;
907 #endif
910 #endif
911 #ifdef INET6
912 if (cm->cmsg_level == IPPROTO_IPV6) {
913 switch(cm->cmsg_type) {
914 case IPV6_PKTINFO:
915 if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
916 continue;
917 memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
918 ifindex = (unsigned int)ipi6.ipi6_ifindex;
919 break;
920 case IPV6_HOPLIMIT:
921 if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
922 continue;
923 if (hoplimit == NULL)
924 break;
925 memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
926 break;
929 #endif
932 /* Find the receiving interface */
933 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
934 if (ifp->index == ifindex)
935 break;
937 if (ifp == NULL)
938 errno = ESRCH;
939 return ifp;
943 xsocket(int domain, int type, int protocol)
945 int s;
946 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
947 int xflags, xtype = type;
948 #endif
950 #ifndef HAVE_SOCK_CLOEXEC
951 if (xtype & SOCK_CLOEXEC)
952 type &= ~SOCK_CLOEXEC;
953 #endif
954 #ifndef HAVE_SOCK_NONBLOCK
955 if (xtype & SOCK_NONBLOCK)
956 type &= ~SOCK_NONBLOCK;
957 #endif
959 if ((s = socket(domain, type, protocol)) == -1)
960 return -1;
962 #ifndef HAVE_SOCK_CLOEXEC
963 if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
964 fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1))
965 goto out;
966 #endif
967 #ifndef HAVE_SOCK_NONBLOCK
968 if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 ||
969 fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1))
970 goto out;
971 #endif
973 return s;
975 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
976 out:
977 close(s);
978 return -1;
979 #endif
983 xsocketpair(int domain, int type, int protocol, int fd[2])
985 int s;
986 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
987 int xflags, xtype = type;
988 #endif
990 #ifndef HAVE_SOCK_CLOEXEC
991 if (xtype & SOCK_CLOEXEC)
992 type &= ~SOCK_CLOEXEC;
993 #endif
994 #ifndef HAVE_SOCK_NONBLOCK
995 if (xtype & SOCK_NONBLOCK)
996 type &= ~SOCK_NONBLOCK;
997 #endif
999 if ((s = socketpair(domain, type, protocol, fd)) == -1)
1000 return -1;
1002 #ifndef HAVE_SOCK_CLOEXEC
1003 if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[0], F_GETFD)) == -1 ||
1004 fcntl(fd[0], F_SETFD, xflags | FD_CLOEXEC) == -1))
1005 goto out;
1006 if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[1], F_GETFD)) == -1 ||
1007 fcntl(fd[1], F_SETFD, xflags | FD_CLOEXEC) == -1))
1008 goto out;
1009 #endif
1010 #ifndef HAVE_SOCK_NONBLOCK
1011 if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[0], F_GETFL)) == -1 ||
1012 fcntl(fd[0], F_SETFL, xflags | O_NONBLOCK) == -1))
1013 goto out;
1014 if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[1], F_GETFL)) == -1 ||
1015 fcntl(fd[1], F_SETFL, xflags | O_NONBLOCK) == -1))
1016 goto out;
1017 #endif
1019 return s;
1021 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
1022 out:
1023 close(fd[0]);
1024 close(fd[1]);
1025 return -1;
1026 #endif