xref: /minix3/external/bsd/dhcpcd/dist/if.c (revision 9f20bfa6c4c442e2e798d91b11c2a5f8d6833a41)
1*9f20bfa6SDavid van Moolenbroek #include <sys/cdefs.h>
2*9f20bfa6SDavid van Moolenbroek  __RCSID("$NetBSD: if.c,v 1.16 2015/09/04 12:25:01 roy Exp $");
3*9f20bfa6SDavid van Moolenbroek 
4*9f20bfa6SDavid van Moolenbroek /*
5*9f20bfa6SDavid van Moolenbroek  * dhcpcd - DHCP client daemon
6*9f20bfa6SDavid van Moolenbroek  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7*9f20bfa6SDavid van Moolenbroek  * All rights reserved
8*9f20bfa6SDavid van Moolenbroek 
9*9f20bfa6SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*9f20bfa6SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*9f20bfa6SDavid van Moolenbroek  * are met:
12*9f20bfa6SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*9f20bfa6SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*9f20bfa6SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*9f20bfa6SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
16*9f20bfa6SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
17*9f20bfa6SDavid van Moolenbroek  *
18*9f20bfa6SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*9f20bfa6SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*9f20bfa6SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*9f20bfa6SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*9f20bfa6SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*9f20bfa6SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*9f20bfa6SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*9f20bfa6SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*9f20bfa6SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*9f20bfa6SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*9f20bfa6SDavid van Moolenbroek  * SUCH DAMAGE.
29*9f20bfa6SDavid van Moolenbroek  */
30*9f20bfa6SDavid van Moolenbroek 
31*9f20bfa6SDavid van Moolenbroek #include <sys/param.h>
32*9f20bfa6SDavid van Moolenbroek #include <sys/types.h>
33*9f20bfa6SDavid van Moolenbroek #include <sys/ioctl.h>
34*9f20bfa6SDavid van Moolenbroek #include <sys/socket.h>
35*9f20bfa6SDavid van Moolenbroek 
36*9f20bfa6SDavid van Moolenbroek #include <net/if.h>
37*9f20bfa6SDavid van Moolenbroek #include <net/if_arp.h>
38*9f20bfa6SDavid van Moolenbroek #include <netinet/in.h>
39*9f20bfa6SDavid van Moolenbroek #ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
40*9f20bfa6SDavid van Moolenbroek #  include <net/if_var.h>
41*9f20bfa6SDavid van Moolenbroek #endif
42*9f20bfa6SDavid van Moolenbroek #ifdef AF_LINK
43*9f20bfa6SDavid van Moolenbroek #  include <net/if_dl.h>
44*9f20bfa6SDavid van Moolenbroek #  include <net/if_types.h>
45*9f20bfa6SDavid van Moolenbroek #  include <netinet/in_var.h>
46*9f20bfa6SDavid van Moolenbroek #endif
47*9f20bfa6SDavid van Moolenbroek #ifdef AF_PACKET
48*9f20bfa6SDavid van Moolenbroek #  include <netpacket/packet.h>
49*9f20bfa6SDavid van Moolenbroek #endif
50*9f20bfa6SDavid van Moolenbroek #ifdef SIOCGIFMEDIA
51*9f20bfa6SDavid van Moolenbroek #  include <net/if_media.h>
52*9f20bfa6SDavid van Moolenbroek #endif
53*9f20bfa6SDavid van Moolenbroek #include <net/route.h>
54*9f20bfa6SDavid van Moolenbroek 
55*9f20bfa6SDavid van Moolenbroek #include <ctype.h>
56*9f20bfa6SDavid van Moolenbroek #include <errno.h>
57*9f20bfa6SDavid van Moolenbroek #include <ifaddrs.h>
58*9f20bfa6SDavid van Moolenbroek #include <fnmatch.h>
59*9f20bfa6SDavid van Moolenbroek #include <stddef.h>
60*9f20bfa6SDavid van Moolenbroek #include <stdio.h>
61*9f20bfa6SDavid van Moolenbroek #include <stdlib.h>
62*9f20bfa6SDavid van Moolenbroek #include <string.h>
63*9f20bfa6SDavid van Moolenbroek #include <unistd.h>
64*9f20bfa6SDavid van Moolenbroek #include <fcntl.h>
65*9f20bfa6SDavid van Moolenbroek 
66*9f20bfa6SDavid van Moolenbroek #include "config.h"
67*9f20bfa6SDavid van Moolenbroek #include "common.h"
68*9f20bfa6SDavid van Moolenbroek #include "dev.h"
69*9f20bfa6SDavid van Moolenbroek #include "dhcp.h"
70*9f20bfa6SDavid van Moolenbroek #include "dhcp6.h"
71*9f20bfa6SDavid van Moolenbroek #include "if.h"
72*9f20bfa6SDavid van Moolenbroek #include "if-options.h"
73*9f20bfa6SDavid van Moolenbroek #include "ipv4.h"
74*9f20bfa6SDavid van Moolenbroek #include "ipv4ll.h"
75*9f20bfa6SDavid van Moolenbroek #include "ipv6nd.h"
76*9f20bfa6SDavid van Moolenbroek 
77*9f20bfa6SDavid van Moolenbroek void
if_free(struct interface * ifp)78*9f20bfa6SDavid van Moolenbroek if_free(struct interface *ifp)
79*9f20bfa6SDavid van Moolenbroek {
80*9f20bfa6SDavid van Moolenbroek 
81*9f20bfa6SDavid van Moolenbroek 	if (ifp == NULL)
82*9f20bfa6SDavid van Moolenbroek 		return;
83*9f20bfa6SDavid van Moolenbroek 	ipv4ll_free(ifp);
84*9f20bfa6SDavid van Moolenbroek 	dhcp_free(ifp);
85*9f20bfa6SDavid van Moolenbroek 	ipv4_free(ifp);
86*9f20bfa6SDavid van Moolenbroek 	dhcp6_free(ifp);
87*9f20bfa6SDavid van Moolenbroek 	ipv6nd_free(ifp);
88*9f20bfa6SDavid van Moolenbroek 	ipv6_free(ifp);
89*9f20bfa6SDavid van Moolenbroek 	free_options(ifp->options);
90*9f20bfa6SDavid van Moolenbroek 	free(ifp);
91*9f20bfa6SDavid van Moolenbroek }
92*9f20bfa6SDavid van Moolenbroek 
93*9f20bfa6SDavid van Moolenbroek int
if_opensockets(struct dhcpcd_ctx * ctx)94*9f20bfa6SDavid van Moolenbroek if_opensockets(struct dhcpcd_ctx *ctx)
95*9f20bfa6SDavid van Moolenbroek {
96*9f20bfa6SDavid van Moolenbroek 
97*9f20bfa6SDavid van Moolenbroek 	if ((ctx->link_fd = if_openlinksocket()) == -1)
98*9f20bfa6SDavid van Moolenbroek 		return -1;
99*9f20bfa6SDavid van Moolenbroek 
100*9f20bfa6SDavid van Moolenbroek 	ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM, 0, O_CLOEXEC);
101*9f20bfa6SDavid van Moolenbroek 	if (ctx->pf_inet_fd == -1)
102*9f20bfa6SDavid van Moolenbroek 		return -1;
103*9f20bfa6SDavid van Moolenbroek 
104*9f20bfa6SDavid van Moolenbroek #if defined(INET6) && defined(BSD)
105*9f20bfa6SDavid van Moolenbroek 	ctx->pf_inet6_fd = xsocket(PF_INET6, SOCK_DGRAM, 0, O_CLOEXEC);
106*9f20bfa6SDavid van Moolenbroek 	if (ctx->pf_inet6_fd == -1)
107*9f20bfa6SDavid van Moolenbroek 		return -1;
108*9f20bfa6SDavid van Moolenbroek #endif
109*9f20bfa6SDavid van Moolenbroek 
110*9f20bfa6SDavid van Moolenbroek #ifdef IFLR_ACTIVE
111*9f20bfa6SDavid van Moolenbroek 	ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0, O_CLOEXEC);
112*9f20bfa6SDavid van Moolenbroek 	if (ctx->pf_link_fd == -1)
113*9f20bfa6SDavid van Moolenbroek 		return -1;
114*9f20bfa6SDavid van Moolenbroek #endif
115*9f20bfa6SDavid van Moolenbroek 
116*9f20bfa6SDavid van Moolenbroek 	return 0;
117*9f20bfa6SDavid van Moolenbroek }
118*9f20bfa6SDavid van Moolenbroek 
119*9f20bfa6SDavid van Moolenbroek int
if_carrier(struct interface * ifp)120*9f20bfa6SDavid van Moolenbroek if_carrier(struct interface *ifp)
121*9f20bfa6SDavid van Moolenbroek {
122*9f20bfa6SDavid van Moolenbroek 	int r;
123*9f20bfa6SDavid van Moolenbroek 	struct ifreq ifr;
124*9f20bfa6SDavid van Moolenbroek #ifdef SIOCGIFMEDIA
125*9f20bfa6SDavid van Moolenbroek 	struct ifmediareq ifmr;
126*9f20bfa6SDavid van Moolenbroek #endif
127*9f20bfa6SDavid van Moolenbroek 
128*9f20bfa6SDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
129*9f20bfa6SDavid van Moolenbroek 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
130*9f20bfa6SDavid van Moolenbroek 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
131*9f20bfa6SDavid van Moolenbroek 		return LINK_UNKNOWN;
132*9f20bfa6SDavid van Moolenbroek 	ifp->flags = (unsigned int)ifr.ifr_flags;
133*9f20bfa6SDavid van Moolenbroek 
134*9f20bfa6SDavid van Moolenbroek #ifdef SIOCGIFMEDIA
135*9f20bfa6SDavid van Moolenbroek 	memset(&ifmr, 0, sizeof(ifmr));
136*9f20bfa6SDavid van Moolenbroek 	strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
137*9f20bfa6SDavid van Moolenbroek 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMEDIA, &ifmr) != -1 &&
138*9f20bfa6SDavid van Moolenbroek 	    ifmr.ifm_status & IFM_AVALID)
139*9f20bfa6SDavid van Moolenbroek 		r = (ifmr.ifm_status & IFM_ACTIVE) ? LINK_UP : LINK_DOWN;
140*9f20bfa6SDavid van Moolenbroek 	else
141*9f20bfa6SDavid van Moolenbroek 		r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_UNKNOWN;
142*9f20bfa6SDavid van Moolenbroek #else
143*9f20bfa6SDavid van Moolenbroek 	r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
144*9f20bfa6SDavid van Moolenbroek #endif
145*9f20bfa6SDavid van Moolenbroek 	return r;
146*9f20bfa6SDavid van Moolenbroek }
147*9f20bfa6SDavid van Moolenbroek 
148*9f20bfa6SDavid van Moolenbroek int
if_setflag(struct interface * ifp,short flag)149*9f20bfa6SDavid van Moolenbroek if_setflag(struct interface *ifp, short flag)
150*9f20bfa6SDavid van Moolenbroek {
151*9f20bfa6SDavid van Moolenbroek 	struct ifreq ifr;
152*9f20bfa6SDavid van Moolenbroek 	int r;
153*9f20bfa6SDavid van Moolenbroek 
154*9f20bfa6SDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
155*9f20bfa6SDavid van Moolenbroek 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
156*9f20bfa6SDavid van Moolenbroek 	r = -1;
157*9f20bfa6SDavid van Moolenbroek 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == 0) {
158*9f20bfa6SDavid van Moolenbroek 		if (flag == 0 || (ifr.ifr_flags & flag) == flag)
159*9f20bfa6SDavid van Moolenbroek 			r = 0;
160*9f20bfa6SDavid van Moolenbroek 		else {
161*9f20bfa6SDavid van Moolenbroek 			ifr.ifr_flags |= flag;
162*9f20bfa6SDavid van Moolenbroek 			if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) ==0)
163*9f20bfa6SDavid van Moolenbroek 				r = 0;
164*9f20bfa6SDavid van Moolenbroek 		}
165*9f20bfa6SDavid van Moolenbroek 		ifp->flags = (unsigned int)ifr.ifr_flags;
166*9f20bfa6SDavid van Moolenbroek 	}
167*9f20bfa6SDavid van Moolenbroek 	return r;
168*9f20bfa6SDavid van Moolenbroek }
169*9f20bfa6SDavid van Moolenbroek 
170*9f20bfa6SDavid van Moolenbroek static int
if_hasconf(struct dhcpcd_ctx * ctx,const char * ifname)171*9f20bfa6SDavid van Moolenbroek if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
172*9f20bfa6SDavid van Moolenbroek {
173*9f20bfa6SDavid van Moolenbroek 	int i;
174*9f20bfa6SDavid van Moolenbroek 
175*9f20bfa6SDavid van Moolenbroek 	for (i = 0; i < ctx->ifcc; i++) {
176*9f20bfa6SDavid van Moolenbroek 		if (strcmp(ctx->ifcv[i], ifname) == 0)
177*9f20bfa6SDavid van Moolenbroek 			return 1;
178*9f20bfa6SDavid van Moolenbroek 	}
179*9f20bfa6SDavid van Moolenbroek 	return 0;
180*9f20bfa6SDavid van Moolenbroek }
181*9f20bfa6SDavid van Moolenbroek 
if_learnaddrs1(struct dhcpcd_ctx * ctx,struct if_head * ifs,struct ifaddrs * ifaddrs)182*9f20bfa6SDavid van Moolenbroek static void if_learnaddrs1(struct dhcpcd_ctx *ctx, struct if_head *ifs,
183*9f20bfa6SDavid van Moolenbroek     struct ifaddrs *ifaddrs)
184*9f20bfa6SDavid van Moolenbroek {
185*9f20bfa6SDavid van Moolenbroek 	struct ifaddrs *ifa;
186*9f20bfa6SDavid van Moolenbroek 	struct interface *ifp;
187*9f20bfa6SDavid van Moolenbroek #ifdef INET
188*9f20bfa6SDavid van Moolenbroek 	const struct sockaddr_in *addr, *net, *dst;
189*9f20bfa6SDavid van Moolenbroek #endif
190*9f20bfa6SDavid van Moolenbroek #ifdef INET6
191*9f20bfa6SDavid van Moolenbroek 	struct sockaddr_in6 *sin6, *net6;
192*9f20bfa6SDavid van Moolenbroek #endif
193*9f20bfa6SDavid van Moolenbroek 	int ifa_flags;
194*9f20bfa6SDavid van Moolenbroek 
195*9f20bfa6SDavid van Moolenbroek 
196*9f20bfa6SDavid van Moolenbroek 	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
197*9f20bfa6SDavid van Moolenbroek 		if (ifa->ifa_addr == NULL)
198*9f20bfa6SDavid van Moolenbroek 			continue;
199*9f20bfa6SDavid van Moolenbroek 		if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
200*9f20bfa6SDavid van Moolenbroek 			continue;
201*9f20bfa6SDavid van Moolenbroek 		switch(ifa->ifa_addr->sa_family) {
202*9f20bfa6SDavid van Moolenbroek #ifdef INET
203*9f20bfa6SDavid van Moolenbroek 		case AF_INET:
204*9f20bfa6SDavid van Moolenbroek 			addr = (const struct sockaddr_in *)
205*9f20bfa6SDavid van Moolenbroek 			    (void *)ifa->ifa_addr;
206*9f20bfa6SDavid van Moolenbroek 			net = (const struct sockaddr_in *)
207*9f20bfa6SDavid van Moolenbroek 			    (void *)ifa->ifa_netmask;
208*9f20bfa6SDavid van Moolenbroek 			if (ifa->ifa_flags & IFF_POINTOPOINT)
209*9f20bfa6SDavid van Moolenbroek 				dst = (const struct sockaddr_in *)
210*9f20bfa6SDavid van Moolenbroek 				    (void *)ifa->ifa_dstaddr;
211*9f20bfa6SDavid van Moolenbroek 			else
212*9f20bfa6SDavid van Moolenbroek 				dst = NULL;
213*9f20bfa6SDavid van Moolenbroek 			ifa_flags = if_addrflags(&addr->sin_addr, ifp);
214*9f20bfa6SDavid van Moolenbroek 			ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
215*9f20bfa6SDavid van Moolenbroek 				&addr->sin_addr,
216*9f20bfa6SDavid van Moolenbroek 				&net->sin_addr,
217*9f20bfa6SDavid van Moolenbroek 				dst ? &dst->sin_addr : NULL, ifa_flags);
218*9f20bfa6SDavid van Moolenbroek 			break;
219*9f20bfa6SDavid van Moolenbroek #endif
220*9f20bfa6SDavid van Moolenbroek #ifdef INET6
221*9f20bfa6SDavid van Moolenbroek 		case AF_INET6:
222*9f20bfa6SDavid van Moolenbroek 			sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
223*9f20bfa6SDavid van Moolenbroek 			net6 = (struct sockaddr_in6 *)(void *)ifa->ifa_netmask;
224*9f20bfa6SDavid van Moolenbroek #ifdef __KAME__
225*9f20bfa6SDavid van Moolenbroek 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
226*9f20bfa6SDavid van Moolenbroek 				/* Remove the scope from the address */
227*9f20bfa6SDavid van Moolenbroek 				sin6->sin6_addr.s6_addr[2] =
228*9f20bfa6SDavid van Moolenbroek 				    sin6->sin6_addr.s6_addr[3] = '\0';
229*9f20bfa6SDavid van Moolenbroek #endif
230*9f20bfa6SDavid van Moolenbroek 			ifa_flags = if_addrflags6(&sin6->sin6_addr, ifp);
231*9f20bfa6SDavid van Moolenbroek 			if (ifa_flags != -1)
232*9f20bfa6SDavid van Moolenbroek 				ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
233*9f20bfa6SDavid van Moolenbroek 				    ifa->ifa_name,
234*9f20bfa6SDavid van Moolenbroek 				    &sin6->sin6_addr,
235*9f20bfa6SDavid van Moolenbroek 				    ipv6_prefixlen(&net6->sin6_addr),
236*9f20bfa6SDavid van Moolenbroek 				    ifa_flags);
237*9f20bfa6SDavid van Moolenbroek 			break;
238*9f20bfa6SDavid van Moolenbroek #endif
239*9f20bfa6SDavid van Moolenbroek 		}
240*9f20bfa6SDavid van Moolenbroek 	}
241*9f20bfa6SDavid van Moolenbroek }
242*9f20bfa6SDavid van Moolenbroek 
243*9f20bfa6SDavid van Moolenbroek struct if_head *
if_discover(struct dhcpcd_ctx * ctx,int argc,char * const * argv)244*9f20bfa6SDavid van Moolenbroek if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
245*9f20bfa6SDavid van Moolenbroek {
246*9f20bfa6SDavid van Moolenbroek 	struct ifaddrs *ifaddrs, *ifa;
247*9f20bfa6SDavid van Moolenbroek 	char *p;
248*9f20bfa6SDavid van Moolenbroek 	int i;
249*9f20bfa6SDavid van Moolenbroek 	struct if_head *ifs;
250*9f20bfa6SDavid van Moolenbroek 	struct interface *ifp;
251*9f20bfa6SDavid van Moolenbroek #ifdef __linux__
252*9f20bfa6SDavid van Moolenbroek 	char ifn[IF_NAMESIZE];
253*9f20bfa6SDavid van Moolenbroek #endif
254*9f20bfa6SDavid van Moolenbroek #ifdef AF_LINK
255*9f20bfa6SDavid van Moolenbroek 	const struct sockaddr_dl *sdl;
256*9f20bfa6SDavid van Moolenbroek #ifdef SIOCGIFPRIORITY
257*9f20bfa6SDavid van Moolenbroek 	struct ifreq ifr;
258*9f20bfa6SDavid van Moolenbroek #endif
259*9f20bfa6SDavid van Moolenbroek #ifdef IFLR_ACTIVE
260*9f20bfa6SDavid van Moolenbroek 	struct if_laddrreq iflr;
261*9f20bfa6SDavid van Moolenbroek #endif
262*9f20bfa6SDavid van Moolenbroek 
263*9f20bfa6SDavid van Moolenbroek #ifdef IFLR_ACTIVE
264*9f20bfa6SDavid van Moolenbroek 	memset(&iflr, 0, sizeof(iflr));
265*9f20bfa6SDavid van Moolenbroek #endif
266*9f20bfa6SDavid van Moolenbroek #elif AF_PACKET
267*9f20bfa6SDavid van Moolenbroek 	const struct sockaddr_ll *sll;
268*9f20bfa6SDavid van Moolenbroek #endif
269*9f20bfa6SDavid van Moolenbroek 
270*9f20bfa6SDavid van Moolenbroek 	if (getifaddrs(&ifaddrs) == -1)
271*9f20bfa6SDavid van Moolenbroek 		return NULL;
272*9f20bfa6SDavid van Moolenbroek 	ifs = malloc(sizeof(*ifs));
273*9f20bfa6SDavid van Moolenbroek 	if (ifs == NULL)
274*9f20bfa6SDavid van Moolenbroek 		return NULL;
275*9f20bfa6SDavid van Moolenbroek 	TAILQ_INIT(ifs);
276*9f20bfa6SDavid van Moolenbroek 
277*9f20bfa6SDavid van Moolenbroek 	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
278*9f20bfa6SDavid van Moolenbroek 		if (ifa->ifa_addr != NULL) {
279*9f20bfa6SDavid van Moolenbroek #ifdef AF_LINK
280*9f20bfa6SDavid van Moolenbroek 			if (ifa->ifa_addr->sa_family != AF_LINK)
281*9f20bfa6SDavid van Moolenbroek 				continue;
282*9f20bfa6SDavid van Moolenbroek #elif AF_PACKET
283*9f20bfa6SDavid van Moolenbroek 			if (ifa->ifa_addr->sa_family != AF_PACKET)
284*9f20bfa6SDavid van Moolenbroek 				continue;
285*9f20bfa6SDavid van Moolenbroek #endif
286*9f20bfa6SDavid van Moolenbroek 		}
287*9f20bfa6SDavid van Moolenbroek 
288*9f20bfa6SDavid van Moolenbroek 		/* It's possible for an interface to have >1 AF_LINK.
289*9f20bfa6SDavid van Moolenbroek 		 * For our purposes, we use the first one. */
290*9f20bfa6SDavid van Moolenbroek 		TAILQ_FOREACH(ifp, ifs, next) {
291*9f20bfa6SDavid van Moolenbroek 			if (strcmp(ifp->name, ifa->ifa_name) == 0)
292*9f20bfa6SDavid van Moolenbroek 				break;
293*9f20bfa6SDavid van Moolenbroek 		}
294*9f20bfa6SDavid van Moolenbroek 		if (ifp)
295*9f20bfa6SDavid van Moolenbroek 			continue;
296*9f20bfa6SDavid van Moolenbroek 
297*9f20bfa6SDavid van Moolenbroek 		if (argc > 0) {
298*9f20bfa6SDavid van Moolenbroek 			for (i = 0; i < argc; i++) {
299*9f20bfa6SDavid van Moolenbroek #ifdef __linux__
300*9f20bfa6SDavid van Moolenbroek 				/* Check the real interface name */
301*9f20bfa6SDavid van Moolenbroek 				strlcpy(ifn, argv[i], sizeof(ifn));
302*9f20bfa6SDavid van Moolenbroek 				p = strchr(ifn, ':');
303*9f20bfa6SDavid van Moolenbroek 				if (p)
304*9f20bfa6SDavid van Moolenbroek 					*p = '\0';
305*9f20bfa6SDavid van Moolenbroek 				if (strcmp(ifn, ifa->ifa_name) == 0)
306*9f20bfa6SDavid van Moolenbroek 					break;
307*9f20bfa6SDavid van Moolenbroek #else
308*9f20bfa6SDavid van Moolenbroek 				if (strcmp(argv[i], ifa->ifa_name) == 0)
309*9f20bfa6SDavid van Moolenbroek 					break;
310*9f20bfa6SDavid van Moolenbroek #endif
311*9f20bfa6SDavid van Moolenbroek 			}
312*9f20bfa6SDavid van Moolenbroek 			if (i == argc)
313*9f20bfa6SDavid van Moolenbroek 				continue;
314*9f20bfa6SDavid van Moolenbroek 			p = argv[i];
315*9f20bfa6SDavid van Moolenbroek 		} else {
316*9f20bfa6SDavid van Moolenbroek 			p = ifa->ifa_name;
317*9f20bfa6SDavid van Moolenbroek #ifdef __linux__
318*9f20bfa6SDavid van Moolenbroek 			strlcpy(ifn, ifa->ifa_name, sizeof(ifn));
319*9f20bfa6SDavid van Moolenbroek #endif
320*9f20bfa6SDavid van Moolenbroek 			/* -1 means we're discovering against a specific
321*9f20bfa6SDavid van Moolenbroek 			 * interface, but we still need the below rules
322*9f20bfa6SDavid van Moolenbroek 			 * to apply. */
323*9f20bfa6SDavid van Moolenbroek 			if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
324*9f20bfa6SDavid van Moolenbroek 				continue;
325*9f20bfa6SDavid van Moolenbroek 		}
326*9f20bfa6SDavid van Moolenbroek 		for (i = 0; i < ctx->ifdc; i++)
327*9f20bfa6SDavid van Moolenbroek 			if (!fnmatch(ctx->ifdv[i], p, 0))
328*9f20bfa6SDavid van Moolenbroek 				break;
329*9f20bfa6SDavid van Moolenbroek 		if (i < ctx->ifdc)
330*9f20bfa6SDavid van Moolenbroek 			continue;
331*9f20bfa6SDavid van Moolenbroek 		for (i = 0; i < ctx->ifac; i++)
332*9f20bfa6SDavid van Moolenbroek 			if (!fnmatch(ctx->ifav[i], p, 0))
333*9f20bfa6SDavid van Moolenbroek 				break;
334*9f20bfa6SDavid van Moolenbroek 		if (ctx->ifac && i == ctx->ifac)
335*9f20bfa6SDavid van Moolenbroek 			continue;
336*9f20bfa6SDavid van Moolenbroek 
337*9f20bfa6SDavid van Moolenbroek 		/* Ensure that the interface name has settled */
338*9f20bfa6SDavid van Moolenbroek 		if (!dev_initialized(ctx, p))
339*9f20bfa6SDavid van Moolenbroek 			continue;
340*9f20bfa6SDavid van Moolenbroek 
341*9f20bfa6SDavid van Moolenbroek 		/* Don't allow loopback or pointopoint unless explicit */
342*9f20bfa6SDavid van Moolenbroek 		if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) {
343*9f20bfa6SDavid van Moolenbroek 			if ((argc == 0 || argc == -1) &&
344*9f20bfa6SDavid van Moolenbroek 			    ctx->ifac == 0 && !if_hasconf(ctx, p))
345*9f20bfa6SDavid van Moolenbroek 				continue;
346*9f20bfa6SDavid van Moolenbroek 		}
347*9f20bfa6SDavid van Moolenbroek 
348*9f20bfa6SDavid van Moolenbroek 		if (if_vimaster(ctx, p) == 1) {
349*9f20bfa6SDavid van Moolenbroek 			logger(ctx, argc ? LOG_ERR : LOG_DEBUG,
350*9f20bfa6SDavid van Moolenbroek 			    "%s: is a Virtual Interface Master, skipping", p);
351*9f20bfa6SDavid van Moolenbroek 			continue;
352*9f20bfa6SDavid van Moolenbroek 		}
353*9f20bfa6SDavid van Moolenbroek 
354*9f20bfa6SDavid van Moolenbroek 		ifp = calloc(1, sizeof(*ifp));
355*9f20bfa6SDavid van Moolenbroek 		if (ifp == NULL) {
356*9f20bfa6SDavid van Moolenbroek 			logger(ctx, LOG_ERR, "%s: %m", __func__);
357*9f20bfa6SDavid van Moolenbroek 			break;
358*9f20bfa6SDavid van Moolenbroek 		}
359*9f20bfa6SDavid van Moolenbroek 		ifp->ctx = ctx;
360*9f20bfa6SDavid van Moolenbroek #ifdef __linux__
361*9f20bfa6SDavid van Moolenbroek 		strlcpy(ifp->name, ifn, sizeof(ifp->name));
362*9f20bfa6SDavid van Moolenbroek 		strlcpy(ifp->alias, p, sizeof(ifp->alias));
363*9f20bfa6SDavid van Moolenbroek #else
364*9f20bfa6SDavid van Moolenbroek 		strlcpy(ifp->name, p, sizeof(ifp->name));
365*9f20bfa6SDavid van Moolenbroek #endif
366*9f20bfa6SDavid van Moolenbroek 		ifp->flags = ifa->ifa_flags;
367*9f20bfa6SDavid van Moolenbroek 		ifp->carrier = if_carrier(ifp);
368*9f20bfa6SDavid van Moolenbroek 
369*9f20bfa6SDavid van Moolenbroek 		if (ifa->ifa_addr != NULL) {
370*9f20bfa6SDavid van Moolenbroek #ifdef AF_LINK
371*9f20bfa6SDavid van Moolenbroek 			sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
372*9f20bfa6SDavid van Moolenbroek 
373*9f20bfa6SDavid van Moolenbroek #ifdef IFLR_ACTIVE
374*9f20bfa6SDavid van Moolenbroek 			/* We need to check for active address */
375*9f20bfa6SDavid van Moolenbroek 			strlcpy(iflr.iflr_name, ifp->name,
376*9f20bfa6SDavid van Moolenbroek 			    sizeof(iflr.iflr_name));
377*9f20bfa6SDavid van Moolenbroek 			memcpy(&iflr.addr, ifa->ifa_addr,
378*9f20bfa6SDavid van Moolenbroek 			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
379*9f20bfa6SDavid van Moolenbroek 			iflr.flags = IFLR_PREFIX;
380*9f20bfa6SDavid van Moolenbroek 			iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
381*9f20bfa6SDavid van Moolenbroek 			if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 ||
382*9f20bfa6SDavid van Moolenbroek 			    !(iflr.flags & IFLR_ACTIVE))
383*9f20bfa6SDavid van Moolenbroek 			{
384*9f20bfa6SDavid van Moolenbroek 				if_free(ifp);
385*9f20bfa6SDavid van Moolenbroek 				continue;
386*9f20bfa6SDavid van Moolenbroek 			}
387*9f20bfa6SDavid van Moolenbroek #endif
388*9f20bfa6SDavid van Moolenbroek 
389*9f20bfa6SDavid van Moolenbroek 			ifp->index = sdl->sdl_index;
390*9f20bfa6SDavid van Moolenbroek 			switch(sdl->sdl_type) {
391*9f20bfa6SDavid van Moolenbroek #ifdef IFT_BRIDGE
392*9f20bfa6SDavid van Moolenbroek 			case IFT_BRIDGE: /* FALLTHROUGH */
393*9f20bfa6SDavid van Moolenbroek #endif
394*9f20bfa6SDavid van Moolenbroek #ifdef IFT_PPP
395*9f20bfa6SDavid van Moolenbroek 			case IFT_PPP: /* FALLTHROUGH */
396*9f20bfa6SDavid van Moolenbroek #endif
397*9f20bfa6SDavid van Moolenbroek #ifdef IFT_PROPVIRTUAL
398*9f20bfa6SDavid van Moolenbroek 			case IFT_PROPVIRTUAL: /* FALLTHROUGH */
399*9f20bfa6SDavid van Moolenbroek #endif
400*9f20bfa6SDavid van Moolenbroek #if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL)
401*9f20bfa6SDavid van Moolenbroek 				/* Don't allow unless explicit */
402*9f20bfa6SDavid van Moolenbroek 				if ((argc == 0 || argc == -1) &&
403*9f20bfa6SDavid van Moolenbroek 				    ctx->ifac == 0 &&
404*9f20bfa6SDavid van Moolenbroek 				    !if_hasconf(ctx, ifp->name))
405*9f20bfa6SDavid van Moolenbroek 				{
406*9f20bfa6SDavid van Moolenbroek 					logger(ifp->ctx, LOG_DEBUG,
407*9f20bfa6SDavid van Moolenbroek 					    "%s: ignoring due to"
408*9f20bfa6SDavid van Moolenbroek 					    " interface type and"
409*9f20bfa6SDavid van Moolenbroek 					    " no config",
410*9f20bfa6SDavid van Moolenbroek 					    ifp->name);
411*9f20bfa6SDavid van Moolenbroek 					if_free(ifp);
412*9f20bfa6SDavid van Moolenbroek 					continue;
413*9f20bfa6SDavid van Moolenbroek 				}
414*9f20bfa6SDavid van Moolenbroek 				/* FALLTHROUGH */
415*9f20bfa6SDavid van Moolenbroek #endif
416*9f20bfa6SDavid van Moolenbroek #ifdef IFT_L2VLAN
417*9f20bfa6SDavid van Moolenbroek 			case IFT_L2VLAN: /* FALLTHROUGH */
418*9f20bfa6SDavid van Moolenbroek #endif
419*9f20bfa6SDavid van Moolenbroek #ifdef IFT_L3IPVLAN
420*9f20bfa6SDavid van Moolenbroek 			case IFT_L3IPVLAN: /* FALLTHROUGH */
421*9f20bfa6SDavid van Moolenbroek #endif
422*9f20bfa6SDavid van Moolenbroek 			case IFT_ETHER:
423*9f20bfa6SDavid van Moolenbroek 				ifp->family = ARPHRD_ETHER;
424*9f20bfa6SDavid van Moolenbroek 				break;
425*9f20bfa6SDavid van Moolenbroek #ifdef IFT_IEEE1394
426*9f20bfa6SDavid van Moolenbroek 			case IFT_IEEE1394:
427*9f20bfa6SDavid van Moolenbroek 				ifp->family = ARPHRD_IEEE1394;
428*9f20bfa6SDavid van Moolenbroek 				break;
429*9f20bfa6SDavid van Moolenbroek #endif
430*9f20bfa6SDavid van Moolenbroek #ifdef IFT_INFINIBAND
431*9f20bfa6SDavid van Moolenbroek 			case IFT_INFINIBAND:
432*9f20bfa6SDavid van Moolenbroek 				ifp->family = ARPHRD_INFINIBAND;
433*9f20bfa6SDavid van Moolenbroek 				break;
434*9f20bfa6SDavid van Moolenbroek #endif
435*9f20bfa6SDavid van Moolenbroek 			default:
436*9f20bfa6SDavid van Moolenbroek 				/* Don't allow unless explicit */
437*9f20bfa6SDavid van Moolenbroek 				if ((argc == 0 || argc == -1) &&
438*9f20bfa6SDavid van Moolenbroek 				    ctx->ifac == 0 &&
439*9f20bfa6SDavid van Moolenbroek 				    !if_hasconf(ctx, ifp->name))
440*9f20bfa6SDavid van Moolenbroek 				{
441*9f20bfa6SDavid van Moolenbroek 					if_free(ifp);
442*9f20bfa6SDavid van Moolenbroek 					continue;
443*9f20bfa6SDavid van Moolenbroek 				}
444*9f20bfa6SDavid van Moolenbroek 				logger(ifp->ctx, LOG_WARNING,
445*9f20bfa6SDavid van Moolenbroek 				    "%s: unsupported interface type %.2x",
446*9f20bfa6SDavid van Moolenbroek 				    ifp->name, sdl->sdl_type);
447*9f20bfa6SDavid van Moolenbroek 				/* Pretend it's ethernet */
448*9f20bfa6SDavid van Moolenbroek 				ifp->family = ARPHRD_ETHER;
449*9f20bfa6SDavid van Moolenbroek 				break;
450*9f20bfa6SDavid van Moolenbroek 			}
451*9f20bfa6SDavid van Moolenbroek 			ifp->hwlen = sdl->sdl_alen;
452*9f20bfa6SDavid van Moolenbroek #ifndef CLLADDR
453*9f20bfa6SDavid van Moolenbroek #  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
454*9f20bfa6SDavid van Moolenbroek #endif
455*9f20bfa6SDavid van Moolenbroek 			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
456*9f20bfa6SDavid van Moolenbroek #elif AF_PACKET
457*9f20bfa6SDavid van Moolenbroek 			sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
458*9f20bfa6SDavid van Moolenbroek 			ifp->index = (unsigned int)sll->sll_ifindex;
459*9f20bfa6SDavid van Moolenbroek 			ifp->family = sll->sll_hatype;
460*9f20bfa6SDavid van Moolenbroek 			ifp->hwlen = sll->sll_halen;
461*9f20bfa6SDavid van Moolenbroek 			if (ifp->hwlen != 0)
462*9f20bfa6SDavid van Moolenbroek 				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
463*9f20bfa6SDavid van Moolenbroek #endif
464*9f20bfa6SDavid van Moolenbroek 		}
465*9f20bfa6SDavid van Moolenbroek #ifdef __linux__
466*9f20bfa6SDavid van Moolenbroek 		/* PPP addresses on Linux don't have hardware addresses */
467*9f20bfa6SDavid van Moolenbroek 		else
468*9f20bfa6SDavid van Moolenbroek 			ifp->index = if_nametoindex(ifp->name);
469*9f20bfa6SDavid van Moolenbroek #endif
470*9f20bfa6SDavid van Moolenbroek 
471*9f20bfa6SDavid van Moolenbroek 		/* We only work on ethernet by default */
472*9f20bfa6SDavid van Moolenbroek 		if (ifp->family != ARPHRD_ETHER) {
473*9f20bfa6SDavid van Moolenbroek 			if ((argc == 0 || argc == -1) &&
474*9f20bfa6SDavid van Moolenbroek 			    ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
475*9f20bfa6SDavid van Moolenbroek 			{
476*9f20bfa6SDavid van Moolenbroek 				if_free(ifp);
477*9f20bfa6SDavid van Moolenbroek 				continue;
478*9f20bfa6SDavid van Moolenbroek 			}
479*9f20bfa6SDavid van Moolenbroek 			switch (ifp->family) {
480*9f20bfa6SDavid van Moolenbroek 			case ARPHRD_IEEE1394:
481*9f20bfa6SDavid van Moolenbroek 			case ARPHRD_INFINIBAND:
482*9f20bfa6SDavid van Moolenbroek #ifdef ARPHRD_LOOPBACK
483*9f20bfa6SDavid van Moolenbroek 			case ARPHRD_LOOPBACK:
484*9f20bfa6SDavid van Moolenbroek #endif
485*9f20bfa6SDavid van Moolenbroek #ifdef ARPHRD_PPP
486*9f20bfa6SDavid van Moolenbroek 			case ARPHRD_PPP:
487*9f20bfa6SDavid van Moolenbroek #endif
488*9f20bfa6SDavid van Moolenbroek 				/* We don't warn for supported families */
489*9f20bfa6SDavid van Moolenbroek 				break;
490*9f20bfa6SDavid van Moolenbroek 
491*9f20bfa6SDavid van Moolenbroek /* IFT already checked */
492*9f20bfa6SDavid van Moolenbroek #ifndef AF_LINK
493*9f20bfa6SDavid van Moolenbroek 			default:
494*9f20bfa6SDavid van Moolenbroek 				logger(ifp->ctx, LOG_WARNING,
495*9f20bfa6SDavid van Moolenbroek 				    "%s: unsupported interface family %.2x",
496*9f20bfa6SDavid van Moolenbroek 				    ifp->name, ifp->family);
497*9f20bfa6SDavid van Moolenbroek 				break;
498*9f20bfa6SDavid van Moolenbroek #endif
499*9f20bfa6SDavid van Moolenbroek 			}
500*9f20bfa6SDavid van Moolenbroek 		}
501*9f20bfa6SDavid van Moolenbroek 
502*9f20bfa6SDavid van Moolenbroek 		if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
503*9f20bfa6SDavid van Moolenbroek 			/* Handle any platform init for the interface */
504*9f20bfa6SDavid van Moolenbroek 			if (if_init(ifp) == -1) {
505*9f20bfa6SDavid van Moolenbroek 				logger(ifp->ctx, LOG_ERR, "%s: if_init: %m", p);
506*9f20bfa6SDavid van Moolenbroek 				if_free(ifp);
507*9f20bfa6SDavid van Moolenbroek 				continue;
508*9f20bfa6SDavid van Moolenbroek 			}
509*9f20bfa6SDavid van Moolenbroek 
510*9f20bfa6SDavid van Moolenbroek 			/* Ensure that the MTU is big enough for DHCP */
511*9f20bfa6SDavid van Moolenbroek 			if (if_getmtu(ifp) < MTU_MIN &&
512*9f20bfa6SDavid van Moolenbroek 			    if_setmtu(ifp, MTU_MIN) == -1)
513*9f20bfa6SDavid van Moolenbroek 			{
514*9f20bfa6SDavid van Moolenbroek 				logger(ifp->ctx, LOG_ERR,
515*9f20bfa6SDavid van Moolenbroek 				    "%s: if_setmtu: %m", p);
516*9f20bfa6SDavid van Moolenbroek 				if_free(ifp);
517*9f20bfa6SDavid van Moolenbroek 				continue;
518*9f20bfa6SDavid van Moolenbroek 			}
519*9f20bfa6SDavid van Moolenbroek 		}
520*9f20bfa6SDavid van Moolenbroek 
521*9f20bfa6SDavid van Moolenbroek #ifdef SIOCGIFPRIORITY
522*9f20bfa6SDavid van Moolenbroek 		/* Respect the interface priority */
523*9f20bfa6SDavid van Moolenbroek 		memset(&ifr, 0, sizeof(ifr));
524*9f20bfa6SDavid van Moolenbroek 		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
525*9f20bfa6SDavid van Moolenbroek 		if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
526*9f20bfa6SDavid van Moolenbroek 			ifp->metric = ifr.ifr_metric;
527*9f20bfa6SDavid van Moolenbroek #else
528*9f20bfa6SDavid van Moolenbroek 		/* We reserve the 100 range for virtual interfaces, if and when
529*9f20bfa6SDavid van Moolenbroek 		 * we can work them out. */
530*9f20bfa6SDavid van Moolenbroek 		ifp->metric = 200 + ifp->index;
531*9f20bfa6SDavid van Moolenbroek 		if (if_getssid(ifp) != -1) {
532*9f20bfa6SDavid van Moolenbroek 			ifp->wireless = 1;
533*9f20bfa6SDavid van Moolenbroek 			ifp->metric += 100;
534*9f20bfa6SDavid van Moolenbroek 		}
535*9f20bfa6SDavid van Moolenbroek #endif
536*9f20bfa6SDavid van Moolenbroek 
537*9f20bfa6SDavid van Moolenbroek 		TAILQ_INSERT_TAIL(ifs, ifp, next);
538*9f20bfa6SDavid van Moolenbroek 	}
539*9f20bfa6SDavid van Moolenbroek 
540*9f20bfa6SDavid van Moolenbroek 	if_learnaddrs1(ctx, ifs, ifaddrs);
541*9f20bfa6SDavid van Moolenbroek 	freeifaddrs(ifaddrs);
542*9f20bfa6SDavid van Moolenbroek 
543*9f20bfa6SDavid van Moolenbroek 	return ifs;
544*9f20bfa6SDavid van Moolenbroek }
545*9f20bfa6SDavid van Moolenbroek 
546*9f20bfa6SDavid van Moolenbroek static struct interface *
if_findindexname(struct if_head * ifaces,unsigned int idx,const char * name)547*9f20bfa6SDavid van Moolenbroek if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
548*9f20bfa6SDavid van Moolenbroek {
549*9f20bfa6SDavid van Moolenbroek 
550*9f20bfa6SDavid van Moolenbroek 	if (ifaces != NULL) {
551*9f20bfa6SDavid van Moolenbroek 		struct interface *ifp;
552*9f20bfa6SDavid van Moolenbroek 
553*9f20bfa6SDavid van Moolenbroek 		TAILQ_FOREACH(ifp, ifaces, next) {
554*9f20bfa6SDavid van Moolenbroek 			if ((name && strcmp(ifp->name, name) == 0) ||
555*9f20bfa6SDavid van Moolenbroek #ifdef __linux__
556*9f20bfa6SDavid van Moolenbroek 			    (name && strcmp(ifp->alias, name) == 0) ||
557*9f20bfa6SDavid van Moolenbroek #endif
558*9f20bfa6SDavid van Moolenbroek 			    (!name && ifp->index == idx))
559*9f20bfa6SDavid van Moolenbroek 				return ifp;
560*9f20bfa6SDavid van Moolenbroek 		}
561*9f20bfa6SDavid van Moolenbroek 	}
562*9f20bfa6SDavid van Moolenbroek 
563*9f20bfa6SDavid van Moolenbroek 	errno = ESRCH;
564*9f20bfa6SDavid van Moolenbroek 	return NULL;
565*9f20bfa6SDavid van Moolenbroek }
566*9f20bfa6SDavid van Moolenbroek 
567*9f20bfa6SDavid van Moolenbroek struct interface *
if_find(struct if_head * ifaces,const char * name)568*9f20bfa6SDavid van Moolenbroek if_find(struct if_head *ifaces, const char *name)
569*9f20bfa6SDavid van Moolenbroek {
570*9f20bfa6SDavid van Moolenbroek 
571*9f20bfa6SDavid van Moolenbroek 	return if_findindexname(ifaces, 0, name);
572*9f20bfa6SDavid van Moolenbroek }
573*9f20bfa6SDavid van Moolenbroek 
574*9f20bfa6SDavid van Moolenbroek struct interface *
if_findindex(struct if_head * ifaces,unsigned int idx)575*9f20bfa6SDavid van Moolenbroek if_findindex(struct if_head *ifaces, unsigned int idx)
576*9f20bfa6SDavid van Moolenbroek {
577*9f20bfa6SDavid van Moolenbroek 
578*9f20bfa6SDavid van Moolenbroek 	return if_findindexname(ifaces, idx, NULL);
579*9f20bfa6SDavid van Moolenbroek }
580*9f20bfa6SDavid van Moolenbroek 
581*9f20bfa6SDavid van Moolenbroek int
if_domtu(const struct interface * ifp,short int mtu)582*9f20bfa6SDavid van Moolenbroek if_domtu(const struct interface *ifp, short int mtu)
583*9f20bfa6SDavid van Moolenbroek {
584*9f20bfa6SDavid van Moolenbroek 	int r;
585*9f20bfa6SDavid van Moolenbroek 	struct ifreq ifr;
586*9f20bfa6SDavid van Moolenbroek 
587*9f20bfa6SDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
588*9f20bfa6SDavid van Moolenbroek 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
589*9f20bfa6SDavid van Moolenbroek 	ifr.ifr_mtu = mtu;
590*9f20bfa6SDavid van Moolenbroek 	r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
591*9f20bfa6SDavid van Moolenbroek 	if (r == -1)
592*9f20bfa6SDavid van Moolenbroek 		return -1;
593*9f20bfa6SDavid van Moolenbroek 	return ifr.ifr_mtu;
594*9f20bfa6SDavid van Moolenbroek }
595*9f20bfa6SDavid van Moolenbroek 
596*9f20bfa6SDavid van Moolenbroek /* Interface comparer for working out ordering. */
597*9f20bfa6SDavid van Moolenbroek static int
if_cmp(const struct interface * si,const struct interface * ti)598*9f20bfa6SDavid van Moolenbroek if_cmp(const struct interface *si, const struct interface *ti)
599*9f20bfa6SDavid van Moolenbroek {
600*9f20bfa6SDavid van Moolenbroek #ifdef INET
601*9f20bfa6SDavid van Moolenbroek 	int r;
602*9f20bfa6SDavid van Moolenbroek #endif
603*9f20bfa6SDavid van Moolenbroek 
604*9f20bfa6SDavid van Moolenbroek 	/* Check carrier status first */
605*9f20bfa6SDavid van Moolenbroek 	if (si->carrier > ti->carrier)
606*9f20bfa6SDavid van Moolenbroek 		return -1;
607*9f20bfa6SDavid van Moolenbroek 	if (si->carrier < ti->carrier)
608*9f20bfa6SDavid van Moolenbroek 		return 1;
609*9f20bfa6SDavid van Moolenbroek 
610*9f20bfa6SDavid van Moolenbroek 	if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
611*9f20bfa6SDavid van Moolenbroek 		return -1;
612*9f20bfa6SDavid van Moolenbroek 	if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
613*9f20bfa6SDavid van Moolenbroek 		return 1;
614*9f20bfa6SDavid van Moolenbroek 	if (RS_STATE_RUNNING(si) && !RS_STATE_RUNNING(ti))
615*9f20bfa6SDavid van Moolenbroek 		return -1;
616*9f20bfa6SDavid van Moolenbroek 	if (!RS_STATE_RUNNING(si) && RS_STATE_RUNNING(ti))
617*9f20bfa6SDavid van Moolenbroek 		return 1;
618*9f20bfa6SDavid van Moolenbroek 	if (D6_STATE_RUNNING(si) && !D6_STATE_RUNNING(ti))
619*9f20bfa6SDavid van Moolenbroek 		return -1;
620*9f20bfa6SDavid van Moolenbroek 	if (!D6_STATE_RUNNING(si) && D6_STATE_RUNNING(ti))
621*9f20bfa6SDavid van Moolenbroek 		return 1;
622*9f20bfa6SDavid van Moolenbroek 
623*9f20bfa6SDavid van Moolenbroek #ifdef INET
624*9f20bfa6SDavid van Moolenbroek 	/* Special attention needed here due to states and IPv4LL. */
625*9f20bfa6SDavid van Moolenbroek 	if ((r = ipv4_ifcmp(si, ti)) != 0)
626*9f20bfa6SDavid van Moolenbroek 		return r;
627*9f20bfa6SDavid van Moolenbroek #endif
628*9f20bfa6SDavid van Moolenbroek 
629*9f20bfa6SDavid van Moolenbroek 	/* Finally, metric */
630*9f20bfa6SDavid van Moolenbroek 	if (si->metric < ti->metric)
631*9f20bfa6SDavid van Moolenbroek 		return -1;
632*9f20bfa6SDavid van Moolenbroek 	if (si->metric > ti->metric)
633*9f20bfa6SDavid van Moolenbroek 		return 1;
634*9f20bfa6SDavid van Moolenbroek 	return 0;
635*9f20bfa6SDavid van Moolenbroek }
636*9f20bfa6SDavid van Moolenbroek 
637*9f20bfa6SDavid van Moolenbroek /* Sort the interfaces into a preferred order - best first, worst last. */
638*9f20bfa6SDavid van Moolenbroek void
if_sortinterfaces(struct dhcpcd_ctx * ctx)639*9f20bfa6SDavid van Moolenbroek if_sortinterfaces(struct dhcpcd_ctx *ctx)
640*9f20bfa6SDavid van Moolenbroek {
641*9f20bfa6SDavid van Moolenbroek 	struct if_head sorted;
642*9f20bfa6SDavid van Moolenbroek 	struct interface *ifp, *ift;
643*9f20bfa6SDavid van Moolenbroek 
644*9f20bfa6SDavid van Moolenbroek 	if (ctx->ifaces == NULL ||
645*9f20bfa6SDavid van Moolenbroek 	    (ifp = TAILQ_FIRST(ctx->ifaces)) == NULL ||
646*9f20bfa6SDavid van Moolenbroek 	    TAILQ_NEXT(ifp, next) == NULL)
647*9f20bfa6SDavid van Moolenbroek 		return;
648*9f20bfa6SDavid van Moolenbroek 
649*9f20bfa6SDavid van Moolenbroek 	TAILQ_INIT(&sorted);
650*9f20bfa6SDavid van Moolenbroek 	TAILQ_REMOVE(ctx->ifaces, ifp, next);
651*9f20bfa6SDavid van Moolenbroek 	TAILQ_INSERT_HEAD(&sorted, ifp, next);
652*9f20bfa6SDavid van Moolenbroek 	while ((ifp = TAILQ_FIRST(ctx->ifaces))) {
653*9f20bfa6SDavid van Moolenbroek 		TAILQ_REMOVE(ctx->ifaces, ifp, next);
654*9f20bfa6SDavid van Moolenbroek 		TAILQ_FOREACH(ift, &sorted, next) {
655*9f20bfa6SDavid van Moolenbroek 			if (if_cmp(ifp, ift) == -1) {
656*9f20bfa6SDavid van Moolenbroek 				TAILQ_INSERT_BEFORE(ift, ifp, next);
657*9f20bfa6SDavid van Moolenbroek 				break;
658*9f20bfa6SDavid van Moolenbroek 			}
659*9f20bfa6SDavid van Moolenbroek 		}
660*9f20bfa6SDavid van Moolenbroek 		if (ift == NULL)
661*9f20bfa6SDavid van Moolenbroek 			TAILQ_INSERT_TAIL(&sorted, ifp, next);
662*9f20bfa6SDavid van Moolenbroek 	}
663*9f20bfa6SDavid van Moolenbroek 	TAILQ_CONCAT(ctx->ifaces, &sorted, next);
664*9f20bfa6SDavid van Moolenbroek }
665*9f20bfa6SDavid van Moolenbroek 
666*9f20bfa6SDavid van Moolenbroek int
xsocket(int domain,int type,int protocol,int flags)667*9f20bfa6SDavid van Moolenbroek xsocket(int domain, int type, int protocol, int flags)
668*9f20bfa6SDavid van Moolenbroek {
669*9f20bfa6SDavid van Moolenbroek #ifdef SOCK_CLOEXEC
670*9f20bfa6SDavid van Moolenbroek 	if (flags & O_CLOEXEC)
671*9f20bfa6SDavid van Moolenbroek 		type |= SOCK_CLOEXEC;
672*9f20bfa6SDavid van Moolenbroek 	if (flags & O_NONBLOCK)
673*9f20bfa6SDavid van Moolenbroek 		type |= SOCK_NONBLOCK;
674*9f20bfa6SDavid van Moolenbroek 
675*9f20bfa6SDavid van Moolenbroek 	return socket(domain, type, protocol);
676*9f20bfa6SDavid van Moolenbroek #else
677*9f20bfa6SDavid van Moolenbroek 	int s, xflags;
678*9f20bfa6SDavid van Moolenbroek 
679*9f20bfa6SDavid van Moolenbroek 	if ((s = socket(domain, type, protocol)) == -1)
680*9f20bfa6SDavid van Moolenbroek 		return -1;
681*9f20bfa6SDavid van Moolenbroek 	if ((flags & O_CLOEXEC) && (xflags = fcntl(s, F_GETFD, 0)) == -1 ||
682*9f20bfa6SDavid van Moolenbroek 	    fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1)
683*9f20bfa6SDavid van Moolenbroek 		goto out;
684*9f20bfa6SDavid van Moolenbroek 	if ((flags & O_NONBLOCK) && (xflags = fcntl(s, F_GETFL, 0)) == -1 ||
685*9f20bfa6SDavid van Moolenbroek 	    fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1)
686*9f20bfa6SDavid van Moolenbroek 		goto out;
687*9f20bfa6SDavid van Moolenbroek 	return s;
688*9f20bfa6SDavid van Moolenbroek out:
689*9f20bfa6SDavid van Moolenbroek 	close(s);
690*9f20bfa6SDavid van Moolenbroek 	return -1;
691*9f20bfa6SDavid van Moolenbroek #endif
692*9f20bfa6SDavid van Moolenbroek }
693