xref: /dragonfly/contrib/dhcpcd/src/if.c (revision 54175cef)
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