18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI * dhcpcd - DHCP client daemon
480aa9461SRoy Marples * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI * All rights reserved
67827cba2SAaron LI
77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI * modification, are permitted provided that the following conditions
97827cba2SAaron LI * are met:
107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI * notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI * documentation and/or other materials provided with the distribution.
157827cba2SAaron LI *
167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI * SUCH DAMAGE.
277827cba2SAaron LI */
287827cba2SAaron LI
297827cba2SAaron LI #include <sys/param.h>
307827cba2SAaron LI #include <sys/types.h>
317827cba2SAaron LI #include <sys/ioctl.h>
327827cba2SAaron LI #include <sys/socket.h>
337827cba2SAaron LI
347f8103cdSRoy Marples #include <fcntl.h> /* Needs to be here for old Linux */
357f8103cdSRoy Marples
367827cba2SAaron LI #include "config.h"
377827cba2SAaron LI
387827cba2SAaron LI #include <net/if.h>
397827cba2SAaron LI #include <net/if_arp.h>
407827cba2SAaron LI #include <netinet/in.h>
417827cba2SAaron LI #ifdef AF_LINK
427827cba2SAaron LI # include <net/if_dl.h>
437827cba2SAaron LI # include <net/if_types.h>
447827cba2SAaron LI # include <netinet/in_var.h>
457827cba2SAaron LI # undef AF_PACKET /* Newer Illumos defines this */
467827cba2SAaron LI #endif
477827cba2SAaron LI #ifdef AF_PACKET
487827cba2SAaron LI # include <netpacket/packet.h>
497827cba2SAaron LI #endif
507827cba2SAaron LI #ifdef SIOCGIFMEDIA
517827cba2SAaron LI # include <net/if_media.h>
527827cba2SAaron LI #endif
537827cba2SAaron LI #include <net/route.h>
547827cba2SAaron LI
557827cba2SAaron LI #include <ctype.h>
567827cba2SAaron LI #include <errno.h>
577827cba2SAaron LI #include <ifaddrs.h>
587827cba2SAaron LI #include <inttypes.h>
597827cba2SAaron LI #include <fnmatch.h>
607827cba2SAaron LI #include <stddef.h>
617827cba2SAaron LI #include <stdio.h>
627827cba2SAaron LI #include <stdlib.h>
637827cba2SAaron LI #include <string.h>
646e63cc1fSRoy Marples #include <syslog.h>
657827cba2SAaron LI #include <unistd.h>
667827cba2SAaron LI
67cc34ba0cSRoy Marples #define ELOOP_QUEUE ELOOP_IF
687827cba2SAaron LI #include "common.h"
69cc34ba0cSRoy Marples #include "eloop.h"
707827cba2SAaron LI #include "dev.h"
717827cba2SAaron LI #include "dhcp.h"
727827cba2SAaron LI #include "dhcp6.h"
737827cba2SAaron LI #include "if.h"
747827cba2SAaron LI #include "if-options.h"
757827cba2SAaron LI #include "ipv4.h"
767827cba2SAaron LI #include "ipv4ll.h"
777827cba2SAaron LI #include "ipv6nd.h"
787827cba2SAaron LI #include "logerr.h"
796e63cc1fSRoy Marples #include "privsep.h"
807827cba2SAaron LI
817827cba2SAaron LI void
if_free(struct interface * ifp)827827cba2SAaron LI if_free(struct interface *ifp)
837827cba2SAaron LI {
847827cba2SAaron LI
857827cba2SAaron LI if (ifp == NULL)
867827cba2SAaron LI return;
878d36e1dfSRoy Marples #ifdef IPV4LL
887827cba2SAaron LI ipv4ll_free(ifp);
898d36e1dfSRoy Marples #endif
908d36e1dfSRoy Marples #ifdef INET
917827cba2SAaron LI dhcp_free(ifp);
927827cba2SAaron LI ipv4_free(ifp);
938d36e1dfSRoy Marples #endif
948d36e1dfSRoy Marples #ifdef DHCP6
957827cba2SAaron LI dhcp6_free(ifp);
968d36e1dfSRoy Marples #endif
978d36e1dfSRoy Marples #ifdef INET6
987827cba2SAaron LI ipv6nd_free(ifp);
997827cba2SAaron LI ipv6_free(ifp);
1008d36e1dfSRoy Marples #endif
1017827cba2SAaron LI rt_freeif(ifp);
1027827cba2SAaron LI free_options(ifp->ctx, ifp->options);
1037827cba2SAaron LI free(ifp);
1047827cba2SAaron LI }
1057827cba2SAaron LI
1067827cba2SAaron LI int
if_opensockets(struct dhcpcd_ctx * ctx)1077827cba2SAaron LI if_opensockets(struct dhcpcd_ctx *ctx)
1087827cba2SAaron LI {
1097827cba2SAaron LI
1107827cba2SAaron LI if (if_opensockets_os(ctx) == -1)
1117827cba2SAaron LI return -1;
1127827cba2SAaron LI
1137f8103cdSRoy Marples #ifdef IFLR_ACTIVE
1147f8103cdSRoy Marples ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1157f8103cdSRoy Marples if (ctx->pf_link_fd == -1)
1167f8103cdSRoy Marples return -1;
1177f8103cdSRoy Marples #ifdef HAVE_CAPSICUM
1187f8103cdSRoy Marples if (ps_rights_limit_ioctl(ctx->pf_link_fd) == -1)
1197f8103cdSRoy Marples return -1;
1207f8103cdSRoy Marples #endif
1217f8103cdSRoy Marples #endif
1227f8103cdSRoy Marples
1237827cba2SAaron LI /* We use this socket for some operations without INET. */
1247827cba2SAaron LI ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1257827cba2SAaron LI if (ctx->pf_inet_fd == -1)
1267827cba2SAaron LI return -1;
1277827cba2SAaron LI
1287827cba2SAaron LI return 0;
1297827cba2SAaron LI }
1307827cba2SAaron LI
1317827cba2SAaron LI void
if_closesockets(struct dhcpcd_ctx * ctx)1327827cba2SAaron LI if_closesockets(struct dhcpcd_ctx *ctx)
1337827cba2SAaron LI {
1347827cba2SAaron LI
135*54175cefSRoy Marples if (ctx->link_fd != -1) {
136*54175cefSRoy Marples eloop_event_delete(ctx->eloop, ctx->link_fd);
137*54175cefSRoy Marples close(ctx->link_fd);
138*54175cefSRoy Marples ctx->link_fd = -1;
1397827cba2SAaron LI }
140*54175cefSRoy Marples
141*54175cefSRoy Marples if (ctx->pf_inet_fd != -1) {
142*54175cefSRoy Marples close(ctx->pf_inet_fd);
143*54175cefSRoy Marples ctx->pf_inet_fd = -1;
144*54175cefSRoy Marples }
145*54175cefSRoy Marples
146*54175cefSRoy Marples if_closesockets_os(ctx);
1477827cba2SAaron LI }
1487827cba2SAaron LI
1497827cba2SAaron LI int
if_ioctl(struct dhcpcd_ctx * ctx,ioctl_request_t req,void * data,size_t len)1506e63cc1fSRoy Marples if_ioctl(struct dhcpcd_ctx *ctx, ioctl_request_t req, void *data, size_t len)
1516e63cc1fSRoy Marples {
1526e63cc1fSRoy Marples
1536e63cc1fSRoy Marples #ifdef PRIVSEP
1546e63cc1fSRoy Marples if (ctx->options & DHCPCD_PRIVSEP)
1556e63cc1fSRoy Marples return (int)ps_root_ioctl(ctx, req, data, len);
1566e63cc1fSRoy Marples #endif
1576e63cc1fSRoy Marples return ioctl(ctx->pf_inet_fd, req, data, len);
1586e63cc1fSRoy Marples }
1596e63cc1fSRoy Marples
1606e63cc1fSRoy Marples int
if_getflags(struct interface * ifp)1618d36e1dfSRoy Marples if_getflags(struct interface *ifp)
1627827cba2SAaron LI {
1638d36e1dfSRoy Marples struct ifreq ifr = { .ifr_flags = 0 };
1647827cba2SAaron LI
1657827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
1667827cba2SAaron LI if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
1678d36e1dfSRoy Marples return -1;
1687827cba2SAaron LI ifp->flags = (unsigned int)ifr.ifr_flags;
1698d36e1dfSRoy Marples return 0;
1707827cba2SAaron LI }
1717827cba2SAaron LI
1727827cba2SAaron LI int
if_setflag(struct interface * ifp,short setflag,short unsetflag)1736e63cc1fSRoy Marples if_setflag(struct interface *ifp, short setflag, short unsetflag)
1747827cba2SAaron LI {
1758d36e1dfSRoy Marples struct ifreq ifr = { .ifr_flags = 0 };
1767a0236bfSRoy Marples short oflags;
1778d36e1dfSRoy Marples
1787827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
1797a0236bfSRoy Marples if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
1807a0236bfSRoy Marples return -1;
1817a0236bfSRoy Marples
1827a0236bfSRoy Marples oflags = ifr.ifr_flags;
1836e63cc1fSRoy Marples ifr.ifr_flags |= setflag;
1846e63cc1fSRoy Marples ifr.ifr_flags &= (short)~unsetflag;
1857a0236bfSRoy Marples if (ifr.ifr_flags != oflags &&
1867a0236bfSRoy Marples if_ioctl(ifp->ctx, SIOCSIFFLAGS, &ifr, sizeof(ifr)) == -1)
1878d36e1dfSRoy Marples return -1;
1888d36e1dfSRoy Marples
189a0d9933aSRoy Marples /*
190a0d9933aSRoy Marples * Do NOT set ifp->flags here.
191a0d9933aSRoy Marples * We need to listen for flag updates from the kernel as they
192a0d9933aSRoy Marples * need to sync with carrier.
193a0d9933aSRoy Marples */
1948d36e1dfSRoy Marples return 0;
1957827cba2SAaron LI }
1967827cba2SAaron LI
19793ddca5eSRoy Marples bool
if_is_link_up(const struct interface * ifp)19893ddca5eSRoy Marples if_is_link_up(const struct interface *ifp)
19993ddca5eSRoy Marples {
20093ddca5eSRoy Marples
20193ddca5eSRoy Marples return ifp->flags & IFF_UP &&
20239994b17SRoy Marples (ifp->carrier != LINK_DOWN ||
20339994b17SRoy Marples (ifp->options != NULL && !(ifp->options->options & DHCPCD_LINK)));
20493ddca5eSRoy Marples }
20593ddca5eSRoy Marples
2066e63cc1fSRoy Marples int
if_randomisemac(struct interface * ifp)2076e63cc1fSRoy Marples if_randomisemac(struct interface *ifp)
2086e63cc1fSRoy Marples {
2096e63cc1fSRoy Marples uint32_t randnum;
2106e63cc1fSRoy Marples size_t hwlen = ifp->hwlen, rlen = 0;
2116e63cc1fSRoy Marples uint8_t buf[HWADDR_LEN], *bp = buf, *rp = (uint8_t *)&randnum;
2126e63cc1fSRoy Marples char sbuf[HWADDR_LEN * 3];
2136e63cc1fSRoy Marples int retval;
2146e63cc1fSRoy Marples
2156e63cc1fSRoy Marples if (hwlen == 0) {
2166e63cc1fSRoy Marples errno = ENOTSUP;
2176e63cc1fSRoy Marples return -1;
2186e63cc1fSRoy Marples }
2196e63cc1fSRoy Marples if (hwlen > sizeof(buf)) {
2206e63cc1fSRoy Marples errno = ENOBUFS;
2216e63cc1fSRoy Marples return -1;
2226e63cc1fSRoy Marples }
2236e63cc1fSRoy Marples
2246e63cc1fSRoy Marples for (; hwlen != 0; hwlen--) {
2256e63cc1fSRoy Marples if (rlen == 0) {
2266e63cc1fSRoy Marples randnum = arc4random();
2276e63cc1fSRoy Marples rp = (uint8_t *)&randnum;
2286e63cc1fSRoy Marples rlen = sizeof(randnum);
2296e63cc1fSRoy Marples }
2306e63cc1fSRoy Marples *bp++ = *rp++;
2316e63cc1fSRoy Marples rlen--;
2326e63cc1fSRoy Marples }
2336e63cc1fSRoy Marples
2346e63cc1fSRoy Marples /* Unicast address and locally administered. */
2356e63cc1fSRoy Marples buf[0] &= 0xFC;
2366e63cc1fSRoy Marples buf[0] |= 0x02;
2376e63cc1fSRoy Marples
2386e63cc1fSRoy Marples logdebugx("%s: hardware address randomised to %s",
2396e63cc1fSRoy Marples ifp->name,
2406e63cc1fSRoy Marples hwaddr_ntoa(buf, ifp->hwlen, sbuf, sizeof(sbuf)));
2416e63cc1fSRoy Marples retval = if_setmac(ifp, buf, ifp->hwlen);
2426e63cc1fSRoy Marples if (retval == 0)
2436e63cc1fSRoy Marples memcpy(ifp->hwaddr, buf, ifp->hwlen);
2446e63cc1fSRoy Marples return retval;
2456e63cc1fSRoy Marples }
2466e63cc1fSRoy Marples
2477827cba2SAaron LI static int
if_hasconf(struct dhcpcd_ctx * ctx,const char * ifname)2487827cba2SAaron LI if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
2497827cba2SAaron LI {
2507827cba2SAaron LI int i;
2517827cba2SAaron LI
2527827cba2SAaron LI for (i = 0; i < ctx->ifcc; i++) {
2537827cba2SAaron LI if (strcmp(ctx->ifcv[i], ifname) == 0)
2547827cba2SAaron LI return 1;
2557827cba2SAaron LI }
2567827cba2SAaron LI return 0;
2577827cba2SAaron LI }
2587827cba2SAaron LI
2597827cba2SAaron LI void
if_markaddrsstale(struct if_head * ifs)2607827cba2SAaron LI if_markaddrsstale(struct if_head *ifs)
2617827cba2SAaron LI {
2627827cba2SAaron LI struct interface *ifp;
2637827cba2SAaron LI
2647827cba2SAaron LI TAILQ_FOREACH(ifp, ifs, next) {
2657827cba2SAaron LI #ifdef INET
2667827cba2SAaron LI ipv4_markaddrsstale(ifp);
2677827cba2SAaron LI #endif
2687827cba2SAaron LI #ifdef INET6
2697827cba2SAaron LI ipv6_markaddrsstale(ifp, 0);
2707827cba2SAaron LI #endif
2717827cba2SAaron LI }
2727827cba2SAaron LI }
2737827cba2SAaron LI
2747827cba2SAaron LI void
if_learnaddrs(struct dhcpcd_ctx * ctx,struct if_head * ifs,struct ifaddrs ** ifaddrs)2757827cba2SAaron LI if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs,
2767827cba2SAaron LI struct ifaddrs **ifaddrs)
2777827cba2SAaron LI {
2787827cba2SAaron LI struct ifaddrs *ifa;
2797827cba2SAaron LI struct interface *ifp;
2807827cba2SAaron LI #ifdef INET
2817827cba2SAaron LI const struct sockaddr_in *addr, *net, *brd;
2827827cba2SAaron LI #endif
2837827cba2SAaron LI #ifdef INET6
2847827cba2SAaron LI struct sockaddr_in6 *sin6, *net6;
2857827cba2SAaron LI #endif
2867827cba2SAaron LI int addrflags;
2877827cba2SAaron LI
2887827cba2SAaron LI for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
2897827cba2SAaron LI if (ifa->ifa_addr == NULL)
2907827cba2SAaron LI continue;
2917827cba2SAaron LI if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
2927827cba2SAaron LI continue;
2937827cba2SAaron LI #ifdef HAVE_IFADDRS_ADDRFLAGS
2947827cba2SAaron LI addrflags = (int)ifa->ifa_addrflags;
2957827cba2SAaron LI #endif
2967827cba2SAaron LI switch(ifa->ifa_addr->sa_family) {
2977827cba2SAaron LI #ifdef INET
2987827cba2SAaron LI case AF_INET:
2997827cba2SAaron LI addr = (void *)ifa->ifa_addr;
3007827cba2SAaron LI net = (void *)ifa->ifa_netmask;
3017827cba2SAaron LI if (ifa->ifa_flags & IFF_POINTOPOINT)
3027827cba2SAaron LI brd = (void *)ifa->ifa_dstaddr;
3037827cba2SAaron LI else
3047827cba2SAaron LI brd = (void *)ifa->ifa_broadaddr;
3057827cba2SAaron LI #ifndef HAVE_IFADDRS_ADDRFLAGS
3067827cba2SAaron LI addrflags = if_addrflags(ifp, &addr->sin_addr,
3077827cba2SAaron LI ifa->ifa_name);
3087827cba2SAaron LI if (addrflags == -1) {
3096e63cc1fSRoy Marples if (errno != EEXIST && errno != EADDRNOTAVAIL) {
3106e63cc1fSRoy Marples char dbuf[INET_ADDRSTRLEN];
3116e63cc1fSRoy Marples const char *dbp;
3126e63cc1fSRoy Marples
3136e63cc1fSRoy Marples dbp = inet_ntop(AF_INET, &addr->sin_addr,
3146e63cc1fSRoy Marples dbuf, sizeof(dbuf));
3156e63cc1fSRoy Marples logerr("%s: if_addrflags: %s%%%s",
3166e63cc1fSRoy Marples __func__, dbp, ifp->name);
3176e63cc1fSRoy Marples }
3187827cba2SAaron LI continue;
3197827cba2SAaron LI }
3207827cba2SAaron LI #endif
3217827cba2SAaron LI ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
3227827cba2SAaron LI &addr->sin_addr, &net->sin_addr,
3237827cba2SAaron LI brd ? &brd->sin_addr : NULL, addrflags, 0);
3247827cba2SAaron LI break;
3257827cba2SAaron LI #endif
3267827cba2SAaron LI #ifdef INET6
3277827cba2SAaron LI case AF_INET6:
3287827cba2SAaron LI sin6 = (void *)ifa->ifa_addr;
3297827cba2SAaron LI net6 = (void *)ifa->ifa_netmask;
3308d36e1dfSRoy Marples
3317827cba2SAaron LI #ifdef __KAME__
3327827cba2SAaron LI if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
3337827cba2SAaron LI /* Remove the scope from the address */
3347827cba2SAaron LI sin6->sin6_addr.s6_addr[2] =
3357827cba2SAaron LI sin6->sin6_addr.s6_addr[3] = '\0';
3367827cba2SAaron LI #endif
3377827cba2SAaron LI #ifndef HAVE_IFADDRS_ADDRFLAGS
3387827cba2SAaron LI addrflags = if_addrflags6(ifp, &sin6->sin6_addr,
3397827cba2SAaron LI ifa->ifa_name);
3407827cba2SAaron LI if (addrflags == -1) {
3416e63cc1fSRoy Marples if (errno != EEXIST && errno != EADDRNOTAVAIL) {
3426e63cc1fSRoy Marples char dbuf[INET6_ADDRSTRLEN];
3436e63cc1fSRoy Marples const char *dbp;
3446e63cc1fSRoy Marples
3456e63cc1fSRoy Marples dbp = inet_ntop(AF_INET6, &sin6->sin6_addr,
3466e63cc1fSRoy Marples dbuf, sizeof(dbuf));
3476e63cc1fSRoy Marples logerr("%s: if_addrflags6: %s%%%s",
3486e63cc1fSRoy Marples __func__, dbp, ifp->name);
3496e63cc1fSRoy Marples }
3507827cba2SAaron LI continue;
3517827cba2SAaron LI }
3527827cba2SAaron LI #endif
3537827cba2SAaron LI ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
3547827cba2SAaron LI ifa->ifa_name, &sin6->sin6_addr,
3557827cba2SAaron LI ipv6_prefixlen(&net6->sin6_addr), addrflags, 0);
3567827cba2SAaron LI break;
3577827cba2SAaron LI #endif
3587827cba2SAaron LI }
3597827cba2SAaron LI }
36080aa9461SRoy Marples }
36180aa9461SRoy Marples
if_freeifaddrs(struct dhcpcd_ctx * ctx,struct ifaddrs ** ifaddrs)36280aa9461SRoy Marples void if_freeifaddrs(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs)
36380aa9461SRoy Marples {
36480aa9461SRoy Marples #ifndef PRIVSEP_GETIFADDRS
36580aa9461SRoy Marples UNUSED(ctx);
36680aa9461SRoy Marples #endif
36780aa9461SRoy Marples
36880aa9461SRoy Marples if (ifaddrs == NULL)
36980aa9461SRoy Marples return;
3707827cba2SAaron LI
3717f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
3727f8103cdSRoy Marples if (IN_PRIVSEP(ctx))
3737f8103cdSRoy Marples free(*ifaddrs);
3747f8103cdSRoy Marples else
3757f8103cdSRoy Marples #endif
3767827cba2SAaron LI freeifaddrs(*ifaddrs);
3777827cba2SAaron LI }
3787827cba2SAaron LI
3797827cba2SAaron LI void
if_deletestaleaddrs(struct if_head * ifs)3807827cba2SAaron LI if_deletestaleaddrs(struct if_head *ifs)
3817827cba2SAaron LI {
3827827cba2SAaron LI struct interface *ifp;
3837827cba2SAaron LI
3847827cba2SAaron LI TAILQ_FOREACH(ifp, ifs, next) {
3857827cba2SAaron LI #ifdef INET
3867827cba2SAaron LI ipv4_deletestaleaddrs(ifp);
3877827cba2SAaron LI #endif
3887827cba2SAaron LI #ifdef INET6
3897827cba2SAaron LI ipv6_deletestaleaddrs(ifp);
3907827cba2SAaron LI #endif
3917827cba2SAaron LI }
3927827cba2SAaron LI }
3937827cba2SAaron LI
3947827cba2SAaron LI bool
if_valid_hwaddr(const uint8_t * hwaddr,size_t hwlen)3957827cba2SAaron LI if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen)
3967827cba2SAaron LI {
3977827cba2SAaron LI size_t i;
3987827cba2SAaron LI bool all_zeros, all_ones;
3997827cba2SAaron LI
4007827cba2SAaron LI all_zeros = all_ones = true;
4017827cba2SAaron LI for (i = 0; i < hwlen; i++) {
4027827cba2SAaron LI if (hwaddr[i] != 0x00)
4037827cba2SAaron LI all_zeros = false;
4047827cba2SAaron LI if (hwaddr[i] != 0xff)
4057827cba2SAaron LI all_ones = false;
4067827cba2SAaron LI if (!all_zeros && !all_ones)
4077827cba2SAaron LI return true;
4087827cba2SAaron LI }
4097827cba2SAaron LI return false;
4107827cba2SAaron LI }
4117827cba2SAaron LI
412cc34ba0cSRoy Marples #if defined(AF_PACKET) && !defined(AF_LINK)
413cc34ba0cSRoy Marples static unsigned int
if_check_arphrd(struct interface * ifp,unsigned int active,bool if_noconf)414cc34ba0cSRoy Marples if_check_arphrd(struct interface *ifp, unsigned int active, bool if_noconf)
415cc34ba0cSRoy Marples {
416cc34ba0cSRoy Marples
417cc34ba0cSRoy Marples switch(ifp->hwtype) {
418cc34ba0cSRoy Marples case ARPHRD_ETHER: /* FALLTHROUGH */
419cc34ba0cSRoy Marples case ARPHRD_IEEE1394: /* FALLTHROUGH */
420cc34ba0cSRoy Marples case ARPHRD_INFINIBAND: /* FALLTHROUGH */
421cc34ba0cSRoy Marples case ARPHRD_NONE: /* FALLTHROUGH */
422cc34ba0cSRoy Marples break;
423cc34ba0cSRoy Marples case ARPHRD_LOOPBACK:
424cc34ba0cSRoy Marples case ARPHRD_PPP:
425a0d9933aSRoy Marples if (if_noconf && active) {
426cc34ba0cSRoy Marples logdebugx("%s: ignoring due to interface type and"
427cc34ba0cSRoy Marples " no config",
428cc34ba0cSRoy Marples ifp->name);
429cc34ba0cSRoy Marples active = IF_INACTIVE;
430cc34ba0cSRoy Marples }
431cc34ba0cSRoy Marples break;
432cc34ba0cSRoy Marples default:
43393ddca5eSRoy Marples if (active) {
43493ddca5eSRoy Marples int i;
43593ddca5eSRoy Marples
436cc34ba0cSRoy Marples if (if_noconf)
437cc34ba0cSRoy Marples active = IF_INACTIVE;
43893ddca5eSRoy Marples i = active ? LOG_WARNING : LOG_DEBUG;
43993ddca5eSRoy Marples logmessage(i, "%s: unsupported"
44093ddca5eSRoy Marples " interface type 0x%.2x",
441cc34ba0cSRoy Marples ifp->name, ifp->hwtype);
44293ddca5eSRoy Marples }
443cc34ba0cSRoy Marples break;
444cc34ba0cSRoy Marples }
445cc34ba0cSRoy Marples
446cc34ba0cSRoy Marples return active;
447cc34ba0cSRoy Marples }
448cc34ba0cSRoy Marples #endif
449cc34ba0cSRoy Marples
4507827cba2SAaron LI struct if_head *
if_discover(struct dhcpcd_ctx * ctx,struct ifaddrs ** ifaddrs,int argc,char * const * argv)4517827cba2SAaron LI if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
4527827cba2SAaron LI int argc, char * const *argv)
4537827cba2SAaron LI {
4547827cba2SAaron LI struct ifaddrs *ifa;
4557827cba2SAaron LI int i;
4567827cba2SAaron LI unsigned int active;
4577827cba2SAaron LI struct if_head *ifs;
4587827cba2SAaron LI struct interface *ifp;
4597827cba2SAaron LI struct if_spec spec;
4601b3b16a2SRoy Marples bool if_noconf;
4617827cba2SAaron LI #ifdef AF_LINK
4627827cba2SAaron LI const struct sockaddr_dl *sdl;
4637827cba2SAaron LI #ifdef IFLR_ACTIVE
4648d36e1dfSRoy Marples struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
4657827cba2SAaron LI #endif
466d4fb1e02SRoy Marples #elif defined(AF_PACKET)
4677827cba2SAaron LI const struct sockaddr_ll *sll;
4687827cba2SAaron LI #endif
469d4fb1e02SRoy Marples #if defined(SIOCGIFPRIORITY)
4708d36e1dfSRoy Marples struct ifreq ifr;
4718d36e1dfSRoy Marples #endif
4727827cba2SAaron LI
4737827cba2SAaron LI if ((ifs = malloc(sizeof(*ifs))) == NULL) {
4747827cba2SAaron LI logerr(__func__);
4757827cba2SAaron LI return NULL;
4767827cba2SAaron LI }
477d4fb1e02SRoy Marples TAILQ_INIT(ifs);
478d4fb1e02SRoy Marples
4797f8103cdSRoy Marples #ifdef PRIVSEP_GETIFADDRS
480d4fb1e02SRoy Marples if (ctx->options & DHCPCD_PRIVSEP) {
481d4fb1e02SRoy Marples if (ps_root_getifaddrs(ctx, ifaddrs) == -1) {
482d4fb1e02SRoy Marples logerr("ps_root_getifaddrs");
4838d36e1dfSRoy Marples free(ifs);
4848d36e1dfSRoy Marples return NULL;
4857827cba2SAaron LI }
486d4fb1e02SRoy Marples } else
487d4fb1e02SRoy Marples #endif
488d4fb1e02SRoy Marples if (getifaddrs(ifaddrs) == -1) {
489d4fb1e02SRoy Marples logerr("getifaddrs");
490d4fb1e02SRoy Marples free(ifs);
491d4fb1e02SRoy Marples return NULL;
492d4fb1e02SRoy Marples }
4938d36e1dfSRoy Marples
4947827cba2SAaron LI for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
4957827cba2SAaron LI if (ifa->ifa_addr != NULL) {
4967827cba2SAaron LI #ifdef AF_LINK
4977827cba2SAaron LI if (ifa->ifa_addr->sa_family != AF_LINK)
4987827cba2SAaron LI continue;
499d4fb1e02SRoy Marples #elif defined(AF_PACKET)
5007827cba2SAaron LI if (ifa->ifa_addr->sa_family != AF_PACKET)
5017827cba2SAaron LI continue;
5027827cba2SAaron LI #endif
5037827cba2SAaron LI }
5047827cba2SAaron LI if (if_nametospec(ifa->ifa_name, &spec) != 0)
5057827cba2SAaron LI continue;
5067827cba2SAaron LI
5077827cba2SAaron LI /* It's possible for an interface to have >1 AF_LINK.
5087827cba2SAaron LI * For our purposes, we use the first one. */
5097827cba2SAaron LI TAILQ_FOREACH(ifp, ifs, next) {
5107827cba2SAaron LI if (strcmp(ifp->name, spec.devname) == 0)
5117827cba2SAaron LI break;
5127827cba2SAaron LI }
5137827cba2SAaron LI if (ifp)
5147827cba2SAaron LI continue;
5157827cba2SAaron LI
5167827cba2SAaron LI if (argc > 0) {
5177827cba2SAaron LI for (i = 0; i < argc; i++) {
5187827cba2SAaron LI if (strcmp(argv[i], spec.devname) == 0)
5197827cba2SAaron LI break;
5207827cba2SAaron LI }
5217827cba2SAaron LI active = (i == argc) ? IF_INACTIVE : IF_ACTIVE_USER;
5227827cba2SAaron LI } else {
5237827cba2SAaron LI /* -1 means we're discovering against a specific
5247827cba2SAaron LI * interface, but we still need the below rules
5257827cba2SAaron LI * to apply. */
5267827cba2SAaron LI if (argc == -1 && strcmp(argv[0], spec.devname) != 0)
5277827cba2SAaron LI continue;
5287827cba2SAaron LI active = ctx->options & DHCPCD_INACTIVE ?
5297827cba2SAaron LI IF_INACTIVE: IF_ACTIVE_USER;
5307827cba2SAaron LI }
5317827cba2SAaron LI
5327827cba2SAaron LI for (i = 0; i < ctx->ifdc; i++)
5337827cba2SAaron LI if (fnmatch(ctx->ifdv[i], spec.devname, 0) == 0)
5347827cba2SAaron LI break;
5357827cba2SAaron LI if (i < ctx->ifdc)
5367827cba2SAaron LI active = IF_INACTIVE;
5377827cba2SAaron LI for (i = 0; i < ctx->ifc; i++)
5387827cba2SAaron LI if (fnmatch(ctx->ifv[i], spec.devname, 0) == 0)
5397827cba2SAaron LI break;
5407827cba2SAaron LI if (ctx->ifc && i == ctx->ifc)
5417827cba2SAaron LI active = IF_INACTIVE;
5427827cba2SAaron LI for (i = 0; i < ctx->ifac; i++)
5437827cba2SAaron LI if (fnmatch(ctx->ifav[i], spec.devname, 0) == 0)
5447827cba2SAaron LI break;
5457827cba2SAaron LI if (ctx->ifac && i == ctx->ifac)
5467827cba2SAaron LI active = IF_INACTIVE;
5477827cba2SAaron LI
5487827cba2SAaron LI #ifdef PLUGIN_DEV
5497827cba2SAaron LI /* Ensure that the interface name has settled */
550a0d9933aSRoy Marples if (!dev_initialised(ctx, spec.devname)) {
551a0d9933aSRoy Marples logdebugx("%s: waiting for interface to initialise",
552a0d9933aSRoy Marples spec.devname);
5537827cba2SAaron LI continue;
554a0d9933aSRoy Marples }
5557827cba2SAaron LI #endif
5567827cba2SAaron LI
5577827cba2SAaron LI if (if_vimaster(ctx, spec.devname) == 1) {
5586e63cc1fSRoy Marples int loglevel = argc != 0 ? LOG_ERR : LOG_DEBUG;
5596e63cc1fSRoy Marples logmessage(loglevel,
5606e63cc1fSRoy Marples "%s: is a Virtual Interface Master, skipping",
5617827cba2SAaron LI spec.devname);
5627827cba2SAaron LI continue;
5637827cba2SAaron LI }
5647827cba2SAaron LI
5651b3b16a2SRoy Marples if_noconf = ((argc == 0 || argc == -1) && ctx->ifac == 0 &&
5661b3b16a2SRoy Marples !if_hasconf(ctx, spec.devname));
5671b3b16a2SRoy Marples
568d4fb1e02SRoy Marples /* Don't allow some reserved interface names unless explicit. */
569a0d9933aSRoy Marples if (if_noconf && if_ignore(ctx, spec.devname)) {
570a0d9933aSRoy Marples logdebugx("%s: ignoring due to interface type and"
571a0d9933aSRoy Marples " no config", spec.devname);
5721b3b16a2SRoy Marples active = IF_INACTIVE;
573a0d9933aSRoy Marples }
5741b3b16a2SRoy Marples
5757827cba2SAaron LI ifp = calloc(1, sizeof(*ifp));
5767827cba2SAaron LI if (ifp == NULL) {
5777827cba2SAaron LI logerr(__func__);
5787827cba2SAaron LI break;
5797827cba2SAaron LI }
5807827cba2SAaron LI ifp->ctx = ctx;
5817827cba2SAaron LI strlcpy(ifp->name, spec.devname, sizeof(ifp->name));
5827827cba2SAaron LI ifp->flags = ifa->ifa_flags;
5837827cba2SAaron LI
5847827cba2SAaron LI if (ifa->ifa_addr != NULL) {
5857827cba2SAaron LI #ifdef AF_LINK
5867827cba2SAaron LI sdl = (const void *)ifa->ifa_addr;
5877827cba2SAaron LI
5887827cba2SAaron LI #ifdef IFLR_ACTIVE
5897827cba2SAaron LI /* We need to check for active address */
5907827cba2SAaron LI strlcpy(iflr.iflr_name, ifp->name,
5917827cba2SAaron LI sizeof(iflr.iflr_name));
5927827cba2SAaron LI memcpy(&iflr.addr, ifa->ifa_addr,
5937827cba2SAaron LI MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
5947827cba2SAaron LI iflr.flags = IFLR_PREFIX;
5957827cba2SAaron LI iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
5967f8103cdSRoy Marples if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 ||
5977827cba2SAaron LI !(iflr.flags & IFLR_ACTIVE))
5987827cba2SAaron LI {
5997827cba2SAaron LI if_free(ifp);
6007827cba2SAaron LI continue;
6017827cba2SAaron LI }
6027827cba2SAaron LI #endif
6037827cba2SAaron LI
6047827cba2SAaron LI ifp->index = sdl->sdl_index;
6057827cba2SAaron LI switch(sdl->sdl_type) {
6067827cba2SAaron LI #ifdef IFT_BRIDGE
6077827cba2SAaron LI case IFT_BRIDGE: /* FALLTHROUGH */
6087827cba2SAaron LI #endif
6097827cba2SAaron LI #ifdef IFT_PROPVIRTUAL
6101b3b16a2SRoy Marples case IFT_PROPVIRTUAL: /* FALLTHROUGH */
6117827cba2SAaron LI #endif
6121b3b16a2SRoy Marples #ifdef IFT_TUNNEL
6131b3b16a2SRoy Marples case IFT_TUNNEL: /* FALLTHROUGH */
6141b3b16a2SRoy Marples #endif
615d4fb1e02SRoy Marples case IFT_LOOP: /* FALLTHROUGH */
6161b3b16a2SRoy Marples case IFT_PPP:
6177827cba2SAaron LI /* Don't allow unless explicit */
618a0d9933aSRoy Marples if (if_noconf && active) {
6197827cba2SAaron LI logdebugx("%s: ignoring due to"
6207827cba2SAaron LI " interface type and"
6217827cba2SAaron LI " no config",
6227827cba2SAaron LI ifp->name);
6237827cba2SAaron LI active = IF_INACTIVE;
6247827cba2SAaron LI }
6251b3b16a2SRoy Marples __fallthrough; /* appease gcc */
6267827cba2SAaron LI /* FALLTHROUGH */
6277827cba2SAaron LI #ifdef IFT_L2VLAN
6287827cba2SAaron LI case IFT_L2VLAN: /* FALLTHROUGH */
6297827cba2SAaron LI #endif
6307827cba2SAaron LI #ifdef IFT_L3IPVLAN
6317827cba2SAaron LI case IFT_L3IPVLAN: /* FALLTHROUGH */
6327827cba2SAaron LI #endif
6337827cba2SAaron LI case IFT_ETHER:
634d4fb1e02SRoy Marples ifp->hwtype = ARPHRD_ETHER;
6357827cba2SAaron LI break;
6367827cba2SAaron LI #ifdef IFT_IEEE1394
6377827cba2SAaron LI case IFT_IEEE1394:
638d4fb1e02SRoy Marples ifp->hwtype = ARPHRD_IEEE1394;
6397827cba2SAaron LI break;
6407827cba2SAaron LI #endif
6417827cba2SAaron LI #ifdef IFT_INFINIBAND
6427827cba2SAaron LI case IFT_INFINIBAND:
643d4fb1e02SRoy Marples ifp->hwtype = ARPHRD_INFINIBAND;
6447827cba2SAaron LI break;
6457827cba2SAaron LI #endif
6467827cba2SAaron LI default:
6477827cba2SAaron LI /* Don't allow unless explicit */
64893ddca5eSRoy Marples if (active) {
6491b3b16a2SRoy Marples if (if_noconf)
6507827cba2SAaron LI active = IF_INACTIVE;
65193ddca5eSRoy Marples i = active ? LOG_WARNING : LOG_DEBUG;
65293ddca5eSRoy Marples logmessage(i, "%s: unsupported"
6531b3b16a2SRoy Marples " interface type 0x%.2x",
6547827cba2SAaron LI ifp->name, sdl->sdl_type);
65593ddca5eSRoy Marples }
6567827cba2SAaron LI /* Pretend it's ethernet */
657d4fb1e02SRoy Marples ifp->hwtype = ARPHRD_ETHER;
6587827cba2SAaron LI break;
6597827cba2SAaron LI }
6607827cba2SAaron LI ifp->hwlen = sdl->sdl_alen;
6617827cba2SAaron LI memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
662d4fb1e02SRoy Marples #elif defined(AF_PACKET)
6637827cba2SAaron LI sll = (const void *)ifa->ifa_addr;
6647827cba2SAaron LI ifp->index = (unsigned int)sll->sll_ifindex;
665d4fb1e02SRoy Marples ifp->hwtype = sll->sll_hatype;
6667827cba2SAaron LI ifp->hwlen = sll->sll_halen;
6677827cba2SAaron LI if (ifp->hwlen != 0)
6687827cba2SAaron LI memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
669cc34ba0cSRoy Marples active = if_check_arphrd(ifp, active, if_noconf);
670d4fb1e02SRoy Marples #endif
6717827cba2SAaron LI }
672cc34ba0cSRoy Marples #ifdef __linux__
673cc34ba0cSRoy Marples else {
674cc34ba0cSRoy Marples struct ifreq ifr = { .ifr_flags = 0 };
675cc34ba0cSRoy Marples
676cc34ba0cSRoy Marples /* This is a huge bug in getifaddrs(3) as there
677cc34ba0cSRoy Marples * is no reason why this can't be returned in
678cc34ba0cSRoy Marples * ifa_addr. */
679cc34ba0cSRoy Marples strlcpy(ifr.ifr_name, ifa->ifa_name,
680cc34ba0cSRoy Marples sizeof(ifr.ifr_name));
681cc34ba0cSRoy Marples if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
682cc34ba0cSRoy Marples logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
683cc34ba0cSRoy Marples ifp->hwtype = ifr.ifr_hwaddr.sa_family;
684cc34ba0cSRoy Marples if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
685cc34ba0cSRoy Marples logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
686cc34ba0cSRoy Marples ifp->index = (unsigned int)ifr.ifr_ifindex;
687cc34ba0cSRoy Marples if_check_arphrd(ifp, active, if_noconf);
688cc34ba0cSRoy Marples }
689cc34ba0cSRoy Marples #endif
6907827cba2SAaron LI
6917827cba2SAaron LI if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
6927827cba2SAaron LI /* Handle any platform init for the interface */
6937827cba2SAaron LI if (active != IF_INACTIVE && if_init(ifp) == -1) {
6947827cba2SAaron LI logerr("%s: if_init", ifp->name);
6957827cba2SAaron LI if_free(ifp);
6967827cba2SAaron LI continue;
6977827cba2SAaron LI }
6987827cba2SAaron LI }
6997827cba2SAaron LI
7007827cba2SAaron LI ifp->vlanid = if_vlanid(ifp);
7017827cba2SAaron LI
7027827cba2SAaron LI #ifdef SIOCGIFPRIORITY
7037827cba2SAaron LI /* Respect the interface priority */
7047827cba2SAaron LI memset(&ifr, 0, sizeof(ifr));
7057827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
706d4fb1e02SRoy Marples if (pioctl(ctx, SIOCGIFPRIORITY, &ifr, sizeof(ifr)) == 0)
7077827cba2SAaron LI ifp->metric = (unsigned int)ifr.ifr_metric;
7087827cba2SAaron LI if_getssid(ifp);
7097827cba2SAaron LI #else
7100aaf6155SRoy Marples /* Leave a low portion for user config */
7110aaf6155SRoy Marples ifp->metric = RTMETRIC_BASE + ifp->index;
7127827cba2SAaron LI if (if_getssid(ifp) != -1) {
7138d36e1dfSRoy Marples ifp->wireless = true;
7140aaf6155SRoy Marples ifp->metric += RTMETRIC_WIRELESS;
7157827cba2SAaron LI }
7167827cba2SAaron LI #endif
7177827cba2SAaron LI
7187827cba2SAaron LI ifp->active = active;
719a0d9933aSRoy Marples ifp->carrier = if_carrier(ifp, ifa->ifa_data);
7207827cba2SAaron LI TAILQ_INSERT_TAIL(ifs, ifp, next);
7217827cba2SAaron LI }
7227827cba2SAaron LI
7237827cba2SAaron LI return ifs;
7247827cba2SAaron LI }
7257827cba2SAaron LI
7266e63cc1fSRoy Marples /*
7276e63cc1fSRoy Marples * eth0.100:2 OR eth0i100:2 (seems to be NetBSD xvif(4) only)
7286e63cc1fSRoy Marples *
7296e63cc1fSRoy Marples * drvname == eth
7306e63cc1fSRoy Marples * devname == eth0.100 OR eth0i100
7316e63cc1fSRoy Marples * ppa = 0
7326e63cc1fSRoy Marples * lun = 2
7336e63cc1fSRoy Marples */
7347827cba2SAaron LI int
if_nametospec(const char * ifname,struct if_spec * spec)7357827cba2SAaron LI if_nametospec(const char *ifname, struct if_spec *spec)
7367827cba2SAaron LI {
7376e63cc1fSRoy Marples char *ep, *pp;
7387827cba2SAaron LI int e;
7397827cba2SAaron LI
7407827cba2SAaron LI if (ifname == NULL || *ifname == '\0' ||
7417827cba2SAaron LI strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >=
7427827cba2SAaron LI sizeof(spec->ifname) ||
7437827cba2SAaron LI strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >=
7447827cba2SAaron LI sizeof(spec->drvname))
7457827cba2SAaron LI {
7467827cba2SAaron LI errno = EINVAL;
7477827cba2SAaron LI return -1;
7487827cba2SAaron LI }
7496e63cc1fSRoy Marples
7506e63cc1fSRoy Marples /* :N is an alias */
7517827cba2SAaron LI ep = strchr(spec->drvname, ':');
7527827cba2SAaron LI if (ep) {
7537827cba2SAaron LI spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e);
7547827cba2SAaron LI if (e != 0) {
7557827cba2SAaron LI errno = e;
7567827cba2SAaron LI return -1;
7577827cba2SAaron LI }
758d4fb1e02SRoy Marples *ep = '\0';
759d4fb1e02SRoy Marples #ifdef __sun
760d4fb1e02SRoy Marples ep--;
761d4fb1e02SRoy Marples #endif
7627827cba2SAaron LI } else {
7637827cba2SAaron LI spec->lun = -1;
764d4fb1e02SRoy Marples #ifdef __sun
7657827cba2SAaron LI ep = spec->drvname + strlen(spec->drvname) - 1;
766d4fb1e02SRoy Marples #endif
7677827cba2SAaron LI }
7686e63cc1fSRoy Marples
7697827cba2SAaron LI strlcpy(spec->devname, spec->drvname, sizeof(spec->devname));
770d4fb1e02SRoy Marples #ifdef __sun
771d4fb1e02SRoy Marples /* Solaris has numbers in the driver name, such as e1000g */
772d4fb1e02SRoy Marples while (ep > spec->drvname && isdigit((int)*ep))
773d4fb1e02SRoy Marples ep--;
774d4fb1e02SRoy Marples if (*ep++ == ':') {
775d4fb1e02SRoy Marples errno = EINVAL;
776d4fb1e02SRoy Marples return -1;
777d4fb1e02SRoy Marples }
778d4fb1e02SRoy Marples #else
779d4fb1e02SRoy Marples /* BSD and Linux no not have numbers in the driver name */
7806e63cc1fSRoy Marples for (ep = spec->drvname; *ep != '\0' && !isdigit((int)*ep); ep++) {
7816e63cc1fSRoy Marples if (*ep == ':') {
7827827cba2SAaron LI errno = EINVAL;
7837827cba2SAaron LI return -1;
7847827cba2SAaron LI }
7856e63cc1fSRoy Marples }
786d4fb1e02SRoy Marples #endif
7876e63cc1fSRoy Marples spec->ppa = (int)strtoi(ep, &pp, 10, 0, INT_MAX, &e);
7887827cba2SAaron LI *ep = '\0';
7897827cba2SAaron LI
790d4fb1e02SRoy Marples #ifndef __sun
7916e63cc1fSRoy Marples /*
7926e63cc1fSRoy Marples * . is used for VLAN style names
7936e63cc1fSRoy Marples * i is used on NetBSD for xvif interfaces
7946e63cc1fSRoy Marples */
7956e63cc1fSRoy Marples if (pp != NULL && (*pp == '.' || *pp == 'i')) {
7966e63cc1fSRoy Marples spec->vlid = (int)strtoi(pp + 1, NULL, 10, 0, INT_MAX, &e);
7976e63cc1fSRoy Marples if (e)
7986e63cc1fSRoy Marples spec->vlid = -1;
7996e63cc1fSRoy Marples } else
800d4fb1e02SRoy Marples #endif
8016e63cc1fSRoy Marples spec->vlid = -1;
8026e63cc1fSRoy Marples
8037827cba2SAaron LI return 0;
8047827cba2SAaron LI }
8057827cba2SAaron LI
8067827cba2SAaron LI static struct interface *
if_findindexname(struct if_head * ifaces,unsigned int idx,const char * name)8077827cba2SAaron LI if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
8087827cba2SAaron LI {
8097827cba2SAaron LI
8107827cba2SAaron LI if (ifaces != NULL) {
8117827cba2SAaron LI struct if_spec spec;
8127827cba2SAaron LI struct interface *ifp;
8137827cba2SAaron LI
8147827cba2SAaron LI if (name && if_nametospec(name, &spec) == -1)
8157827cba2SAaron LI return NULL;
8167827cba2SAaron LI
8177827cba2SAaron LI TAILQ_FOREACH(ifp, ifaces, next) {
8187827cba2SAaron LI if ((name && strcmp(ifp->name, spec.devname) == 0) ||
8197827cba2SAaron LI (!name && ifp->index == idx))
8207827cba2SAaron LI return ifp;
8217827cba2SAaron LI }
8227827cba2SAaron LI }
8237827cba2SAaron LI
8247827cba2SAaron LI errno = ENXIO;
8257827cba2SAaron LI return NULL;
8267827cba2SAaron LI }
8277827cba2SAaron LI
8287827cba2SAaron LI struct interface *
if_find(struct if_head * ifaces,const char * name)8297827cba2SAaron LI if_find(struct if_head *ifaces, const char *name)
8307827cba2SAaron LI {
8317827cba2SAaron LI
8327827cba2SAaron LI return if_findindexname(ifaces, 0, name);
8337827cba2SAaron LI }
8347827cba2SAaron LI
8357827cba2SAaron LI struct interface *
if_findindex(struct if_head * ifaces,unsigned int idx)8367827cba2SAaron LI if_findindex(struct if_head *ifaces, unsigned int idx)
8377827cba2SAaron LI {
8387827cba2SAaron LI
8397827cba2SAaron LI return if_findindexname(ifaces, idx, NULL);
8407827cba2SAaron LI }
8417827cba2SAaron LI
8427827cba2SAaron LI struct interface *
if_loopback(struct dhcpcd_ctx * ctx)8437827cba2SAaron LI if_loopback(struct dhcpcd_ctx *ctx)
8447827cba2SAaron LI {
8457827cba2SAaron LI struct interface *ifp;
8467827cba2SAaron LI
8477827cba2SAaron LI TAILQ_FOREACH(ifp, ctx->ifaces, next) {
8487827cba2SAaron LI if (ifp->flags & IFF_LOOPBACK)
8497827cba2SAaron LI return ifp;
8507827cba2SAaron LI }
8517827cba2SAaron LI return NULL;
8527827cba2SAaron LI }
8537827cba2SAaron LI
8547827cba2SAaron LI int
if_domtu(const struct interface * ifp,short int mtu)8557827cba2SAaron LI if_domtu(const struct interface *ifp, short int mtu)
8567827cba2SAaron LI {
8577827cba2SAaron LI int r;
8587827cba2SAaron LI struct ifreq ifr;
8597827cba2SAaron LI
8608d36e1dfSRoy Marples #ifdef __sun
8618d36e1dfSRoy Marples if (mtu == 0)
8628d36e1dfSRoy Marples return if_mtu_os(ifp);
8638d36e1dfSRoy Marples #endif
8648d36e1dfSRoy Marples
8657827cba2SAaron LI memset(&ifr, 0, sizeof(ifr));
8667827cba2SAaron LI strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
8677827cba2SAaron LI ifr.ifr_mtu = mtu;
8686e63cc1fSRoy Marples if (mtu != 0)
8696e63cc1fSRoy Marples r = if_ioctl(ifp->ctx, SIOCSIFMTU, &ifr, sizeof(ifr));
8706e63cc1fSRoy Marples else
871d4fb1e02SRoy Marples r = pioctl(ifp->ctx, SIOCGIFMTU, &ifr, sizeof(ifr));
872d4fb1e02SRoy Marples
8737827cba2SAaron LI if (r == -1)
8747827cba2SAaron LI return -1;
8757827cba2SAaron LI return ifr.ifr_mtu;
8767827cba2SAaron LI }
8777827cba2SAaron LI
8788d36e1dfSRoy Marples #ifdef ALIAS_ADDR
8798d36e1dfSRoy Marples int
if_makealias(char * alias,size_t alias_len,const char * ifname,int lun)8808d36e1dfSRoy Marples if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
8817827cba2SAaron LI {
8827827cba2SAaron LI
8838d36e1dfSRoy Marples if (lun == 0)
8848d36e1dfSRoy Marples return strlcpy(alias, ifname, alias_len);
8858d36e1dfSRoy Marples return snprintf(alias, alias_len, "%s:%u", ifname, lun);
8867827cba2SAaron LI }
8878d36e1dfSRoy Marples #endif
8887827cba2SAaron LI
8898d36e1dfSRoy Marples struct interface *
if_findifpfromcmsg(struct dhcpcd_ctx * ctx,struct msghdr * msg,int * hoplimit)8908d36e1dfSRoy Marples if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
8917827cba2SAaron LI {
8928d36e1dfSRoy Marples struct cmsghdr *cm;
8938d36e1dfSRoy Marples unsigned int ifindex = 0;
8948d36e1dfSRoy Marples struct interface *ifp;
895b9ccd228SRoy Marples #ifdef INET
896b9ccd228SRoy Marples #ifdef IP_RECVIF
897b9ccd228SRoy Marples struct sockaddr_dl sdl;
898b9ccd228SRoy Marples #else
8998d36e1dfSRoy Marples struct in_pktinfo ipi;
9008d36e1dfSRoy Marples #endif
901b9ccd228SRoy Marples #endif
9028d36e1dfSRoy Marples #ifdef INET6
9038d36e1dfSRoy Marples struct in6_pktinfo ipi6;
9048d36e1dfSRoy Marples #else
9058d36e1dfSRoy Marples UNUSED(hoplimit);
9068d36e1dfSRoy Marples #endif
9077827cba2SAaron LI
9088d36e1dfSRoy Marples for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
9098d36e1dfSRoy Marples cm;
9108d36e1dfSRoy Marples cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
9118d36e1dfSRoy Marples {
912b9ccd228SRoy Marples #ifdef INET
9138d36e1dfSRoy Marples if (cm->cmsg_level == IPPROTO_IP) {
9148d36e1dfSRoy Marples switch(cm->cmsg_type) {
915b9ccd228SRoy Marples #ifdef IP_RECVIF
916b9ccd228SRoy Marples case IP_RECVIF:
917b9ccd228SRoy Marples if (cm->cmsg_len <
918b9ccd228SRoy Marples offsetof(struct sockaddr_dl, sdl_index) +
919b9ccd228SRoy Marples sizeof(sdl.sdl_index))
920b9ccd228SRoy Marples continue;
921b9ccd228SRoy Marples memcpy(&sdl, CMSG_DATA(cm),
922b9ccd228SRoy Marples MIN(sizeof(sdl), cm->cmsg_len));
923b9ccd228SRoy Marples ifindex = sdl.sdl_index;
924b9ccd228SRoy Marples break;
925b9ccd228SRoy Marples #else
9268d36e1dfSRoy Marples case IP_PKTINFO:
9278d36e1dfSRoy Marples if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
9288d36e1dfSRoy Marples continue;
9298d36e1dfSRoy Marples memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
9308d36e1dfSRoy Marples ifindex = (unsigned int)ipi.ipi_ifindex;
9317827cba2SAaron LI break;
932b9ccd228SRoy Marples #endif
9337827cba2SAaron LI }
9347827cba2SAaron LI }
9358d36e1dfSRoy Marples #endif
9368d36e1dfSRoy Marples #ifdef INET6
9378d36e1dfSRoy Marples if (cm->cmsg_level == IPPROTO_IPV6) {
9388d36e1dfSRoy Marples switch(cm->cmsg_type) {
9398d36e1dfSRoy Marples case IPV6_PKTINFO:
9408d36e1dfSRoy Marples if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
9418d36e1dfSRoy Marples continue;
9428d36e1dfSRoy Marples memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
9438d36e1dfSRoy Marples ifindex = (unsigned int)ipi6.ipi6_ifindex;
9448d36e1dfSRoy Marples break;
9458d36e1dfSRoy Marples case IPV6_HOPLIMIT:
9468d36e1dfSRoy Marples if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
9478d36e1dfSRoy Marples continue;
9488d36e1dfSRoy Marples if (hoplimit == NULL)
9498d36e1dfSRoy Marples break;
9508d36e1dfSRoy Marples memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
9518d36e1dfSRoy Marples break;
9527827cba2SAaron LI }
9538d36e1dfSRoy Marples }
9548d36e1dfSRoy Marples #endif
9558d36e1dfSRoy Marples }
9568d36e1dfSRoy Marples
9578d36e1dfSRoy Marples /* Find the receiving interface */
9588d36e1dfSRoy Marples TAILQ_FOREACH(ifp, ctx->ifaces, next) {
9598d36e1dfSRoy Marples if (ifp->index == ifindex)
9608d36e1dfSRoy Marples break;
9618d36e1dfSRoy Marples }
9628d36e1dfSRoy Marples if (ifp == NULL)
9638d36e1dfSRoy Marples errno = ESRCH;
9648d36e1dfSRoy Marples return ifp;
9657827cba2SAaron LI }
9667827cba2SAaron LI
9677827cba2SAaron LI int
xsocket(int domain,int type,int protocol)9687827cba2SAaron LI xsocket(int domain, int type, int protocol)
9697827cba2SAaron LI {
9707827cba2SAaron LI int s;
9717827cba2SAaron LI #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
9727827cba2SAaron LI int xflags, xtype = type;
9737827cba2SAaron LI #endif
9747827cba2SAaron LI
9757827cba2SAaron LI #ifndef HAVE_SOCK_CLOEXEC
9767827cba2SAaron LI if (xtype & SOCK_CLOEXEC)
9777827cba2SAaron LI type &= ~SOCK_CLOEXEC;
9787827cba2SAaron LI #endif
9797827cba2SAaron LI #ifndef HAVE_SOCK_NONBLOCK
9807827cba2SAaron LI if (xtype & SOCK_NONBLOCK)
9817827cba2SAaron LI type &= ~SOCK_NONBLOCK;
9827827cba2SAaron LI #endif
9837827cba2SAaron LI
9847827cba2SAaron LI if ((s = socket(domain, type, protocol)) == -1)
9857827cba2SAaron LI return -1;
986*54175cefSRoy Marples #ifdef DEBUG_FD
987*54175cefSRoy Marples logerrx("pid %d fd=%d domain=%d type=%d protocol=%d",
988*54175cefSRoy Marples getpid(), s, domain, type, protocol);
989*54175cefSRoy Marples #endif
9907827cba2SAaron LI
9917827cba2SAaron LI #ifndef HAVE_SOCK_CLOEXEC
9927827cba2SAaron LI if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
9937827cba2SAaron LI fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1))
9947827cba2SAaron LI goto out;
9957827cba2SAaron LI #endif
9967827cba2SAaron LI #ifndef HAVE_SOCK_NONBLOCK
9977827cba2SAaron LI if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 ||
9987827cba2SAaron LI fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1))
9997827cba2SAaron LI goto out;
10007827cba2SAaron LI #endif
10017827cba2SAaron LI
10027827cba2SAaron LI return s;
10037827cba2SAaron LI
10047827cba2SAaron LI #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
10057827cba2SAaron LI out:
10067827cba2SAaron LI close(s);
10077827cba2SAaron LI return -1;
10087827cba2SAaron LI #endif
10097827cba2SAaron LI }
1010b8b69544SRoy Marples
1011b8b69544SRoy Marples int
xsocketpair(int domain,int type,int protocol,int fd[2])1012b8b69544SRoy Marples xsocketpair(int domain, int type, int protocol, int fd[2])
1013b8b69544SRoy Marples {
1014b8b69544SRoy Marples int s;
1015b8b69544SRoy Marples #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
1016b8b69544SRoy Marples int xflags, xtype = type;
1017b8b69544SRoy Marples #endif
1018b8b69544SRoy Marples
1019b8b69544SRoy Marples #ifndef HAVE_SOCK_CLOEXEC
1020b8b69544SRoy Marples if (xtype & SOCK_CLOEXEC)
1021b8b69544SRoy Marples type &= ~SOCK_CLOEXEC;
1022b8b69544SRoy Marples #endif
1023b8b69544SRoy Marples #ifndef HAVE_SOCK_NONBLOCK
1024b8b69544SRoy Marples if (xtype & SOCK_NONBLOCK)
1025b8b69544SRoy Marples type &= ~SOCK_NONBLOCK;
1026b8b69544SRoy Marples #endif
1027b8b69544SRoy Marples
1028b8b69544SRoy Marples if ((s = socketpair(domain, type, protocol, fd)) == -1)
1029b8b69544SRoy Marples return -1;
1030b8b69544SRoy Marples
1031*54175cefSRoy Marples #ifdef DEBUG_FD
1032*54175cefSRoy Marples logerrx("pid %d fd[0]=%d fd[1]=%d", getpid(), fd[0], fd[1]);
1033*54175cefSRoy Marples #endif
1034*54175cefSRoy Marples
1035b8b69544SRoy Marples #ifndef HAVE_SOCK_CLOEXEC
1036b8b69544SRoy Marples if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[0], F_GETFD)) == -1 ||
1037b8b69544SRoy Marples fcntl(fd[0], F_SETFD, xflags | FD_CLOEXEC) == -1))
1038b8b69544SRoy Marples goto out;
1039b8b69544SRoy Marples if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[1], F_GETFD)) == -1 ||
1040b8b69544SRoy Marples fcntl(fd[1], F_SETFD, xflags | FD_CLOEXEC) == -1))
1041b8b69544SRoy Marples goto out;
1042b8b69544SRoy Marples #endif
1043b8b69544SRoy Marples #ifndef HAVE_SOCK_NONBLOCK
1044b8b69544SRoy Marples if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[0], F_GETFL)) == -1 ||
1045b8b69544SRoy Marples fcntl(fd[0], F_SETFL, xflags | O_NONBLOCK) == -1))
1046b8b69544SRoy Marples goto out;
1047b8b69544SRoy Marples if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(fd[1], F_GETFL)) == -1 ||
1048b8b69544SRoy Marples fcntl(fd[1], F_SETFL, xflags | O_NONBLOCK) == -1))
1049b8b69544SRoy Marples goto out;
1050b8b69544SRoy Marples #endif
1051b8b69544SRoy Marples
1052b8b69544SRoy Marples return s;
1053b8b69544SRoy Marples
1054b8b69544SRoy Marples #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
1055b8b69544SRoy Marples out:
1056b8b69544SRoy Marples close(fd[0]);
1057b8b69544SRoy Marples close(fd[1]);
1058b8b69544SRoy Marples return -1;
1059b8b69544SRoy Marples #endif
1060b8b69544SRoy Marples }
1061