xref: /xnu-12377.61.12/tests/net_test_lib.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1*4d495c6eSApple OSS Distributions /*
2*4d495c6eSApple OSS Distributions  * Copyright (c) 2019-2025 Apple Inc. All rights reserved.
3*4d495c6eSApple OSS Distributions  *
4*4d495c6eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4d495c6eSApple OSS Distributions  *
6*4d495c6eSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4d495c6eSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4d495c6eSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4d495c6eSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4d495c6eSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4d495c6eSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4d495c6eSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4d495c6eSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4d495c6eSApple OSS Distributions  *
15*4d495c6eSApple OSS Distributions  * Please obtain a copy of the License at
16*4d495c6eSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4d495c6eSApple OSS Distributions  *
18*4d495c6eSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4d495c6eSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4d495c6eSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4d495c6eSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4d495c6eSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4d495c6eSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4d495c6eSApple OSS Distributions  * limitations under the License.
25*4d495c6eSApple OSS Distributions  *
26*4d495c6eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4d495c6eSApple OSS Distributions  */
28*4d495c6eSApple OSS Distributions 
29*4d495c6eSApple OSS Distributions #include "net_test_lib.h"
30*4d495c6eSApple OSS Distributions #include "inet_transfer.h"
31*4d495c6eSApple OSS Distributions #include "bpflib.h"
32*4d495c6eSApple OSS Distributions #include "in_cksum.h"
33*4d495c6eSApple OSS Distributions #include <net/if_fake_var.h>
34*4d495c6eSApple OSS Distributions #include <net/if_vlan_var.h>
35*4d495c6eSApple OSS Distributions #include <net/if_bridgevar.h>
36*4d495c6eSApple OSS Distributions 
37*4d495c6eSApple OSS Distributions #define RTM_BUFLEN (sizeof(struct rt_msghdr) + 6 * SOCK_MAXADDRLEN)
38*4d495c6eSApple OSS Distributions 
39*4d495c6eSApple OSS Distributions #define ROUNDUP(a) \
40*4d495c6eSApple OSS Distributions ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
41*4d495c6eSApple OSS Distributions 
42*4d495c6eSApple OSS Distributions bool G_debug;
43*4d495c6eSApple OSS Distributions 
44*4d495c6eSApple OSS Distributions struct in_addr inet_class_c_subnet_mask = {
45*4d495c6eSApple OSS Distributions 	.s_addr = htonl(IN_CLASSC_NET)
46*4d495c6eSApple OSS Distributions };
47*4d495c6eSApple OSS Distributions 
48*4d495c6eSApple OSS Distributions ether_addr_t ether_broadcast = {
49*4d495c6eSApple OSS Distributions 	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
50*4d495c6eSApple OSS Distributions };
51*4d495c6eSApple OSS Distributions 
52*4d495c6eSApple OSS Distributions /*
53*4d495c6eSApple OSS Distributions  * local utility functions
54*4d495c6eSApple OSS Distributions  */
55*4d495c6eSApple OSS Distributions static void
siocll_start(int s,const char * ifname)56*4d495c6eSApple OSS Distributions siocll_start(int s, const char * ifname)
57*4d495c6eSApple OSS Distributions {
58*4d495c6eSApple OSS Distributions 	struct in6_aliasreq     ifra_in6;
59*4d495c6eSApple OSS Distributions 	int                     result;
60*4d495c6eSApple OSS Distributions 
61*4d495c6eSApple OSS Distributions 	bzero(&ifra_in6, sizeof(ifra_in6));
62*4d495c6eSApple OSS Distributions 	strncpy(ifra_in6.ifra_name, ifname, sizeof(ifra_in6.ifra_name));
63*4d495c6eSApple OSS Distributions 	result = ioctl(s, SIOCLL_START, &ifra_in6);
64*4d495c6eSApple OSS Distributions 	T_QUIET;
65*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(result, "SIOCLL_START %s", ifname);
66*4d495c6eSApple OSS Distributions }
67*4d495c6eSApple OSS Distributions 
68*4d495c6eSApple OSS Distributions static void
nd_flags_set(int s,const char * if_name,uint32_t set_flags,uint32_t clear_flags)69*4d495c6eSApple OSS Distributions nd_flags_set(int s, const char * if_name,
70*4d495c6eSApple OSS Distributions     uint32_t set_flags, uint32_t clear_flags)
71*4d495c6eSApple OSS Distributions {
72*4d495c6eSApple OSS Distributions 	uint32_t                new_flags;
73*4d495c6eSApple OSS Distributions 	struct in6_ndireq       nd;
74*4d495c6eSApple OSS Distributions 	int                     result;
75*4d495c6eSApple OSS Distributions 
76*4d495c6eSApple OSS Distributions 	bzero(&nd, sizeof(nd));
77*4d495c6eSApple OSS Distributions 	strncpy(nd.ifname, if_name, sizeof(nd.ifname));
78*4d495c6eSApple OSS Distributions 	result = ioctl(s, SIOCGIFINFO_IN6, &nd);
79*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(result, "SIOCGIFINFO_IN6(%s)", if_name);
80*4d495c6eSApple OSS Distributions 	new_flags = nd.ndi.flags;
81*4d495c6eSApple OSS Distributions 	if (set_flags) {
82*4d495c6eSApple OSS Distributions 		new_flags |= set_flags;
83*4d495c6eSApple OSS Distributions 	}
84*4d495c6eSApple OSS Distributions 	if (clear_flags) {
85*4d495c6eSApple OSS Distributions 		new_flags &= ~clear_flags;
86*4d495c6eSApple OSS Distributions 	}
87*4d495c6eSApple OSS Distributions 	if (new_flags != nd.ndi.flags) {
88*4d495c6eSApple OSS Distributions 		nd.ndi.flags = new_flags;
89*4d495c6eSApple OSS Distributions 		result = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
90*4d495c6eSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(result,
91*4d495c6eSApple OSS Distributions 		    "SIOCSIFINFO_FLAGS(%s) 0x%x",
92*4d495c6eSApple OSS Distributions 		    if_name, nd.ndi.flags);
93*4d495c6eSApple OSS Distributions 	}
94*4d495c6eSApple OSS Distributions }
95*4d495c6eSApple OSS Distributions 
96*4d495c6eSApple OSS Distributions 
97*4d495c6eSApple OSS Distributions static void
siocprotoattach_in6(int s,const char * name)98*4d495c6eSApple OSS Distributions siocprotoattach_in6(int s, const char * name)
99*4d495c6eSApple OSS Distributions {
100*4d495c6eSApple OSS Distributions 	struct in6_aliasreq ifra;
101*4d495c6eSApple OSS Distributions 	int                 result;
102*4d495c6eSApple OSS Distributions 
103*4d495c6eSApple OSS Distributions 	bzero(&ifra, sizeof(ifra));
104*4d495c6eSApple OSS Distributions 	strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
105*4d495c6eSApple OSS Distributions 	result = ioctl(s, SIOCPROTOATTACH_IN6, &ifra);
106*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(result, "SIOCPROTOATTACH_IN6(%s)", name);
107*4d495c6eSApple OSS Distributions }
108*4d495c6eSApple OSS Distributions 
109*4d495c6eSApple OSS Distributions static void
sioc_a_or_d_ifaddr(int s,char * ifname,struct in_addr addr,struct in_addr mask,bool add)110*4d495c6eSApple OSS Distributions sioc_a_or_d_ifaddr(int s, char *ifname, struct in_addr addr, struct in_addr mask,
111*4d495c6eSApple OSS Distributions     bool add)
112*4d495c6eSApple OSS Distributions {
113*4d495c6eSApple OSS Distributions 	struct ifaliasreq       ifra;
114*4d495c6eSApple OSS Distributions 	char                    ntopbuf_ip[INET_ADDRSTRLEN];
115*4d495c6eSApple OSS Distributions 	char                    ntopbuf_mask[INET_ADDRSTRLEN];
116*4d495c6eSApple OSS Distributions 	unsigned long           request;
117*4d495c6eSApple OSS Distributions 	const char *            request_str;
118*4d495c6eSApple OSS Distributions 	int                     ret;
119*4d495c6eSApple OSS Distributions 	struct sockaddr_in *    sin;
120*4d495c6eSApple OSS Distributions 
121*4d495c6eSApple OSS Distributions 	bzero(&ifra, sizeof(ifra));
122*4d495c6eSApple OSS Distributions 	strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
123*4d495c6eSApple OSS Distributions 
124*4d495c6eSApple OSS Distributions 	sin = (struct sockaddr_in *)(void *)&ifra.ifra_addr;
125*4d495c6eSApple OSS Distributions 	sin->sin_len = sizeof(*sin);
126*4d495c6eSApple OSS Distributions 	sin->sin_family = AF_INET;
127*4d495c6eSApple OSS Distributions 	sin->sin_addr = addr;
128*4d495c6eSApple OSS Distributions 
129*4d495c6eSApple OSS Distributions 	sin = (struct sockaddr_in *)(void *)&ifra.ifra_mask;
130*4d495c6eSApple OSS Distributions 	sin->sin_len = sizeof(*sin);
131*4d495c6eSApple OSS Distributions 	sin->sin_family = AF_INET;
132*4d495c6eSApple OSS Distributions 	sin->sin_addr = mask;
133*4d495c6eSApple OSS Distributions 
134*4d495c6eSApple OSS Distributions 	if (add) {
135*4d495c6eSApple OSS Distributions 		request = SIOCAIFADDR;
136*4d495c6eSApple OSS Distributions 		request_str = "SIOCAIFADDR";
137*4d495c6eSApple OSS Distributions 	} else {
138*4d495c6eSApple OSS Distributions 		request = SIOCDIFADDR;
139*4d495c6eSApple OSS Distributions 		request_str = "SIOCDIFADDR";
140*4d495c6eSApple OSS Distributions 	}
141*4d495c6eSApple OSS Distributions 	ret = ioctl(s, request, &ifra);
142*4d495c6eSApple OSS Distributions 	inet_ntop(AF_INET, &addr, ntopbuf_ip, sizeof(ntopbuf_ip));
143*4d495c6eSApple OSS Distributions 	inet_ntop(AF_INET, &sin->sin_addr, ntopbuf_mask, sizeof(ntopbuf_mask));
144*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "%s %s %s %s", request_str,
145*4d495c6eSApple OSS Distributions 	    ifname, ntopbuf_ip, ntopbuf_mask);
146*4d495c6eSApple OSS Distributions }
147*4d495c6eSApple OSS Distributions 
148*4d495c6eSApple OSS Distributions static void
siocaifaddr(int s,char * ifname,struct in_addr addr,struct in_addr mask)149*4d495c6eSApple OSS Distributions siocaifaddr(int s, char *ifname, struct in_addr addr, struct in_addr mask)
150*4d495c6eSApple OSS Distributions {
151*4d495c6eSApple OSS Distributions 	sioc_a_or_d_ifaddr(s, ifname, addr, mask, true);
152*4d495c6eSApple OSS Distributions }
153*4d495c6eSApple OSS Distributions 
154*4d495c6eSApple OSS Distributions static void
siocdifaddr(int s,char * ifname,struct in_addr addr,struct in_addr mask)155*4d495c6eSApple OSS Distributions siocdifaddr(int s, char *ifname, struct in_addr addr, struct in_addr mask)
156*4d495c6eSApple OSS Distributions {
157*4d495c6eSApple OSS Distributions 	sioc_a_or_d_ifaddr(s, ifname, addr, mask, false);
158*4d495c6eSApple OSS Distributions }
159*4d495c6eSApple OSS Distributions 
160*4d495c6eSApple OSS Distributions 
161*4d495c6eSApple OSS Distributions /*
162*4d495c6eSApple OSS Distributions  * utility functions
163*4d495c6eSApple OSS Distributions  */
164*4d495c6eSApple OSS Distributions 
165*4d495c6eSApple OSS Distributions #define NO_SOCKET       (-1)
166*4d495c6eSApple OSS Distributions 
167*4d495c6eSApple OSS Distributions static int
_dgram_socket_get(int * sock_p,int af)168*4d495c6eSApple OSS Distributions _dgram_socket_get(int * sock_p, int af)
169*4d495c6eSApple OSS Distributions {
170*4d495c6eSApple OSS Distributions 	int     sock = *sock_p;
171*4d495c6eSApple OSS Distributions 
172*4d495c6eSApple OSS Distributions 	if (sock != NO_SOCKET) {
173*4d495c6eSApple OSS Distributions 		goto done;
174*4d495c6eSApple OSS Distributions 	}
175*4d495c6eSApple OSS Distributions 	sock = *sock_p = socket(af, SOCK_DGRAM, 0);
176*4d495c6eSApple OSS Distributions 	T_QUIET;
177*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(sock,
178*4d495c6eSApple OSS Distributions 	    "socket(SOCK_DGRAM, %s, 0)",
179*4d495c6eSApple OSS Distributions 	    af == AF_INET ? "AF_INET" : "AF_INET6");
180*4d495c6eSApple OSS Distributions done:
181*4d495c6eSApple OSS Distributions 	return sock;
182*4d495c6eSApple OSS Distributions }
183*4d495c6eSApple OSS Distributions 
184*4d495c6eSApple OSS Distributions static void
_socket_close(int * sock_p)185*4d495c6eSApple OSS Distributions _socket_close(int * sock_p)
186*4d495c6eSApple OSS Distributions {
187*4d495c6eSApple OSS Distributions 	int sock = *sock_p;
188*4d495c6eSApple OSS Distributions 
189*4d495c6eSApple OSS Distributions 	if (sock != NO_SOCKET) {
190*4d495c6eSApple OSS Distributions 		close(sock);
191*4d495c6eSApple OSS Distributions 		*sock_p = NO_SOCKET;
192*4d495c6eSApple OSS Distributions 	}
193*4d495c6eSApple OSS Distributions }
194*4d495c6eSApple OSS Distributions 
195*4d495c6eSApple OSS Distributions static int inet_dgram_socket = NO_SOCKET;
196*4d495c6eSApple OSS Distributions 
197*4d495c6eSApple OSS Distributions int
inet_dgram_socket_get(void)198*4d495c6eSApple OSS Distributions inet_dgram_socket_get(void)
199*4d495c6eSApple OSS Distributions {
200*4d495c6eSApple OSS Distributions 	return _dgram_socket_get(&inet_dgram_socket, AF_INET);
201*4d495c6eSApple OSS Distributions }
202*4d495c6eSApple OSS Distributions 
203*4d495c6eSApple OSS Distributions void
inet_dgram_socket_close(void)204*4d495c6eSApple OSS Distributions inet_dgram_socket_close(void)
205*4d495c6eSApple OSS Distributions {
206*4d495c6eSApple OSS Distributions 	_socket_close(&inet_dgram_socket);
207*4d495c6eSApple OSS Distributions }
208*4d495c6eSApple OSS Distributions 
209*4d495c6eSApple OSS Distributions 
210*4d495c6eSApple OSS Distributions static int inet6_dgram_socket = NO_SOCKET;
211*4d495c6eSApple OSS Distributions 
212*4d495c6eSApple OSS Distributions int
inet6_dgram_socket_get(void)213*4d495c6eSApple OSS Distributions inet6_dgram_socket_get(void)
214*4d495c6eSApple OSS Distributions {
215*4d495c6eSApple OSS Distributions 	return _dgram_socket_get(&inet6_dgram_socket, AF_INET6);
216*4d495c6eSApple OSS Distributions }
217*4d495c6eSApple OSS Distributions 
218*4d495c6eSApple OSS Distributions void
inet6_dgram_socket_close(void)219*4d495c6eSApple OSS Distributions inet6_dgram_socket_close(void)
220*4d495c6eSApple OSS Distributions {
221*4d495c6eSApple OSS Distributions 	_socket_close(&inet6_dgram_socket);
222*4d495c6eSApple OSS Distributions }
223*4d495c6eSApple OSS Distributions 
224*4d495c6eSApple OSS Distributions u_int
ethernet_udp4_frame_populate(void * buf,size_t buf_len,const ether_addr_t * src,struct in_addr src_ip,uint16_t src_port,const ether_addr_t * dst,struct in_addr dst_ip,uint16_t dst_port,const void * data,u_int data_len)225*4d495c6eSApple OSS Distributions ethernet_udp4_frame_populate(void * buf, size_t buf_len,
226*4d495c6eSApple OSS Distributions     const ether_addr_t * src,
227*4d495c6eSApple OSS Distributions     struct in_addr src_ip,
228*4d495c6eSApple OSS Distributions     uint16_t src_port,
229*4d495c6eSApple OSS Distributions     const ether_addr_t * dst,
230*4d495c6eSApple OSS Distributions     struct in_addr dst_ip,
231*4d495c6eSApple OSS Distributions     uint16_t dst_port,
232*4d495c6eSApple OSS Distributions     const void * data, u_int data_len)
233*4d495c6eSApple OSS Distributions {
234*4d495c6eSApple OSS Distributions 	ether_header_t *        eh_p;
235*4d495c6eSApple OSS Distributions 	u_int                   frame_length;
236*4d495c6eSApple OSS Distributions 	static int              ip_id;
237*4d495c6eSApple OSS Distributions 	ip_udp_header_t *       ip_udp;
238*4d495c6eSApple OSS Distributions 	char *                  payload;
239*4d495c6eSApple OSS Distributions 	udp_pseudo_hdr_t *      udp_pseudo;
240*4d495c6eSApple OSS Distributions 
241*4d495c6eSApple OSS Distributions 	frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)) + data_len;
242*4d495c6eSApple OSS Distributions 	if (buf_len < frame_length) {
243*4d495c6eSApple OSS Distributions 		return 0;
244*4d495c6eSApple OSS Distributions 	}
245*4d495c6eSApple OSS Distributions 
246*4d495c6eSApple OSS Distributions 	/* determine frame offsets */
247*4d495c6eSApple OSS Distributions 	eh_p = (ether_header_t *)buf;
248*4d495c6eSApple OSS Distributions 	ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
249*4d495c6eSApple OSS Distributions 	udp_pseudo = (udp_pseudo_hdr_t *)(void *)
250*4d495c6eSApple OSS Distributions 	    (((char *)&ip_udp->udp) - sizeof(*udp_pseudo));
251*4d495c6eSApple OSS Distributions 	payload = (char *)(eh_p + 1) + sizeof(*ip_udp);
252*4d495c6eSApple OSS Distributions 
253*4d495c6eSApple OSS Distributions 	/* ethernet_header */
254*4d495c6eSApple OSS Distributions 	bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
255*4d495c6eSApple OSS Distributions 	bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
256*4d495c6eSApple OSS Distributions 	eh_p->ether_type = htons(ETHERTYPE_IP);
257*4d495c6eSApple OSS Distributions 
258*4d495c6eSApple OSS Distributions 	/* copy the data */
259*4d495c6eSApple OSS Distributions 	bcopy(data, payload, data_len);
260*4d495c6eSApple OSS Distributions 
261*4d495c6eSApple OSS Distributions 	/* fill in UDP pseudo header (gets overwritten by IP header below) */
262*4d495c6eSApple OSS Distributions 	bcopy(&src_ip, &udp_pseudo->src_ip, sizeof(src_ip));
263*4d495c6eSApple OSS Distributions 	bcopy(&dst_ip, &udp_pseudo->dst_ip, sizeof(dst_ip));
264*4d495c6eSApple OSS Distributions 	udp_pseudo->zero = 0;
265*4d495c6eSApple OSS Distributions 	udp_pseudo->proto = IPPROTO_UDP;
266*4d495c6eSApple OSS Distributions 	udp_pseudo->length = htons(sizeof(ip_udp->udp) + data_len);
267*4d495c6eSApple OSS Distributions 
268*4d495c6eSApple OSS Distributions 	/* fill in UDP header */
269*4d495c6eSApple OSS Distributions 	ip_udp->udp.uh_sport = htons(src_port);
270*4d495c6eSApple OSS Distributions 	ip_udp->udp.uh_dport = htons(dst_port);
271*4d495c6eSApple OSS Distributions 	ip_udp->udp.uh_ulen = htons(sizeof(ip_udp->udp) + data_len);
272*4d495c6eSApple OSS Distributions 	ip_udp->udp.uh_sum = 0;
273*4d495c6eSApple OSS Distributions 	ip_udp->udp.uh_sum = in_cksum(udp_pseudo, (int)(sizeof(*udp_pseudo)
274*4d495c6eSApple OSS Distributions 	    + sizeof(ip_udp->udp) + data_len));
275*4d495c6eSApple OSS Distributions 
276*4d495c6eSApple OSS Distributions 	/* fill in IP header */
277*4d495c6eSApple OSS Distributions 	bzero(ip_udp, sizeof(ip_udp->ip));
278*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_v = IPVERSION;
279*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_hl = sizeof(struct ip) >> 2;
280*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_ttl = MAXTTL;
281*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_p = IPPROTO_UDP;
282*4d495c6eSApple OSS Distributions 	bcopy(&src_ip, &ip_udp->ip.ip_src, sizeof(src_ip));
283*4d495c6eSApple OSS Distributions 	bcopy(&dst_ip, &ip_udp->ip.ip_dst, sizeof(dst_ip));
284*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_len = htons(sizeof(*ip_udp) + data_len);
285*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_id = htons(ip_id++);
286*4d495c6eSApple OSS Distributions 
287*4d495c6eSApple OSS Distributions 	/* compute the IP checksum */
288*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_sum = 0; /* needs to be zero for checksum */
289*4d495c6eSApple OSS Distributions 	ip_udp->ip.ip_sum = in_cksum(&ip_udp->ip, sizeof(ip_udp->ip));
290*4d495c6eSApple OSS Distributions 
291*4d495c6eSApple OSS Distributions 	return frame_length;
292*4d495c6eSApple OSS Distributions }
293*4d495c6eSApple OSS Distributions 
294*4d495c6eSApple OSS Distributions u_int
ethernet_udp6_frame_populate(void * buf,size_t buf_len,const ether_addr_t * src,struct in6_addr * src_ip,uint16_t src_port,const ether_addr_t * dst,struct in6_addr * dst_ip,uint16_t dst_port,const void * data,u_int data_len)295*4d495c6eSApple OSS Distributions ethernet_udp6_frame_populate(void * buf, size_t buf_len,
296*4d495c6eSApple OSS Distributions     const ether_addr_t * src,
297*4d495c6eSApple OSS Distributions     struct in6_addr *src_ip,
298*4d495c6eSApple OSS Distributions     uint16_t src_port,
299*4d495c6eSApple OSS Distributions     const ether_addr_t * dst,
300*4d495c6eSApple OSS Distributions     struct in6_addr * dst_ip,
301*4d495c6eSApple OSS Distributions     uint16_t dst_port,
302*4d495c6eSApple OSS Distributions     const void * data, u_int data_len)
303*4d495c6eSApple OSS Distributions {
304*4d495c6eSApple OSS Distributions 	ether_header_t *        eh_p;
305*4d495c6eSApple OSS Distributions 	u_int                   frame_length;
306*4d495c6eSApple OSS Distributions 	ip6_udp_header_t *      ip6_udp;
307*4d495c6eSApple OSS Distributions 	char *                  payload;
308*4d495c6eSApple OSS Distributions 	udp6_pseudo_hdr_t *     udp6_pseudo;
309*4d495c6eSApple OSS Distributions 
310*4d495c6eSApple OSS Distributions 	frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)) + data_len;
311*4d495c6eSApple OSS Distributions 	if (buf_len < frame_length) {
312*4d495c6eSApple OSS Distributions 		return 0;
313*4d495c6eSApple OSS Distributions 	}
314*4d495c6eSApple OSS Distributions 
315*4d495c6eSApple OSS Distributions 	/* determine frame offsets */
316*4d495c6eSApple OSS Distributions 	eh_p = (ether_header_t *)buf;
317*4d495c6eSApple OSS Distributions 	ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
318*4d495c6eSApple OSS Distributions 	udp6_pseudo = (udp6_pseudo_hdr_t *)(void *)
319*4d495c6eSApple OSS Distributions 	    (((char *)&ip6_udp->udp) - sizeof(*udp6_pseudo));
320*4d495c6eSApple OSS Distributions 	payload = (char *)(eh_p + 1) + sizeof(*ip6_udp);
321*4d495c6eSApple OSS Distributions 
322*4d495c6eSApple OSS Distributions 	/* ethernet_header */
323*4d495c6eSApple OSS Distributions 	bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
324*4d495c6eSApple OSS Distributions 	bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
325*4d495c6eSApple OSS Distributions 	eh_p->ether_type = htons(ETHERTYPE_IPV6);
326*4d495c6eSApple OSS Distributions 
327*4d495c6eSApple OSS Distributions 	/* copy the data */
328*4d495c6eSApple OSS Distributions 	bcopy(data, payload, data_len);
329*4d495c6eSApple OSS Distributions 
330*4d495c6eSApple OSS Distributions 	/* fill in UDP pseudo header (gets overwritten by IP header below) */
331*4d495c6eSApple OSS Distributions 	bcopy(src_ip, &udp6_pseudo->src_ip, sizeof(*src_ip));
332*4d495c6eSApple OSS Distributions 	bcopy(dst_ip, &udp6_pseudo->dst_ip, sizeof(*dst_ip));
333*4d495c6eSApple OSS Distributions 	udp6_pseudo->zero = 0;
334*4d495c6eSApple OSS Distributions 	udp6_pseudo->proto = IPPROTO_UDP;
335*4d495c6eSApple OSS Distributions 	udp6_pseudo->length = htons(sizeof(ip6_udp->udp) + data_len);
336*4d495c6eSApple OSS Distributions 
337*4d495c6eSApple OSS Distributions 	/* fill in UDP header */
338*4d495c6eSApple OSS Distributions 	ip6_udp->udp.uh_sport = htons(src_port);
339*4d495c6eSApple OSS Distributions 	ip6_udp->udp.uh_dport = htons(dst_port);
340*4d495c6eSApple OSS Distributions 	ip6_udp->udp.uh_ulen = htons(sizeof(ip6_udp->udp) + data_len);
341*4d495c6eSApple OSS Distributions 	ip6_udp->udp.uh_sum = 0;
342*4d495c6eSApple OSS Distributions 	ip6_udp->udp.uh_sum = in_cksum(udp6_pseudo, (int)(sizeof(*udp6_pseudo)
343*4d495c6eSApple OSS Distributions 	    + sizeof(ip6_udp->udp) + data_len));
344*4d495c6eSApple OSS Distributions 
345*4d495c6eSApple OSS Distributions 	/* fill in IP header */
346*4d495c6eSApple OSS Distributions 	bzero(&ip6_udp->ip6, sizeof(ip6_udp->ip6));
347*4d495c6eSApple OSS Distributions 	ip6_udp->ip6.ip6_vfc = IPV6_VERSION;
348*4d495c6eSApple OSS Distributions 	ip6_udp->ip6.ip6_nxt = IPPROTO_UDP;
349*4d495c6eSApple OSS Distributions 	bcopy(src_ip, &ip6_udp->ip6.ip6_src, sizeof(*src_ip));
350*4d495c6eSApple OSS Distributions 	bcopy(dst_ip, &ip6_udp->ip6.ip6_dst, sizeof(*dst_ip));
351*4d495c6eSApple OSS Distributions 	ip6_udp->ip6.ip6_plen = htons(sizeof(struct udphdr) + data_len);
352*4d495c6eSApple OSS Distributions 	/* ip6_udp->ip6.ip6_flow = ? */
353*4d495c6eSApple OSS Distributions 	return frame_length;
354*4d495c6eSApple OSS Distributions }
355*4d495c6eSApple OSS Distributions 
356*4d495c6eSApple OSS Distributions /**
357*4d495c6eSApple OSS Distributions ** interface management
358*4d495c6eSApple OSS Distributions **/
359*4d495c6eSApple OSS Distributions 
360*4d495c6eSApple OSS Distributions void
ifnet_get_lladdr(const char * ifname,ether_addr_t * eaddr)361*4d495c6eSApple OSS Distributions ifnet_get_lladdr(const char * ifname, ether_addr_t * eaddr)
362*4d495c6eSApple OSS Distributions {
363*4d495c6eSApple OSS Distributions 	int err;
364*4d495c6eSApple OSS Distributions 	struct ifreq ifr;
365*4d495c6eSApple OSS Distributions 	int s = inet_dgram_socket_get();
366*4d495c6eSApple OSS Distributions 
367*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
368*4d495c6eSApple OSS Distributions 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
369*4d495c6eSApple OSS Distributions 	ifr.ifr_addr.sa_family = AF_LINK;
370*4d495c6eSApple OSS Distributions 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
371*4d495c6eSApple OSS Distributions 	err = ioctl(s, SIOCGIFLLADDR, &ifr);
372*4d495c6eSApple OSS Distributions 	T_QUIET;
373*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(err, "SIOCGIFLLADDR %s", ifname);
374*4d495c6eSApple OSS Distributions 	bcopy(ifr.ifr_addr.sa_data, eaddr->octet, ETHER_ADDR_LEN);
375*4d495c6eSApple OSS Distributions 	return;
376*4d495c6eSApple OSS Distributions }
377*4d495c6eSApple OSS Distributions 
378*4d495c6eSApple OSS Distributions int
ifnet_set_lladdr(const char * ifname,ether_addr_t * eaddr)379*4d495c6eSApple OSS Distributions ifnet_set_lladdr(const char * ifname, ether_addr_t * eaddr)
380*4d495c6eSApple OSS Distributions {
381*4d495c6eSApple OSS Distributions 	int err;
382*4d495c6eSApple OSS Distributions 	int this_errno = 0;
383*4d495c6eSApple OSS Distributions 	struct ifreq ifr;
384*4d495c6eSApple OSS Distributions 	int s = inet_dgram_socket_get();
385*4d495c6eSApple OSS Distributions 
386*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
387*4d495c6eSApple OSS Distributions 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
388*4d495c6eSApple OSS Distributions 	ifr.ifr_addr.sa_family = AF_LINK;
389*4d495c6eSApple OSS Distributions 	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
390*4d495c6eSApple OSS Distributions 	bcopy(eaddr->octet, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
391*4d495c6eSApple OSS Distributions 	err = ioctl(s, SIOCSIFLLADDR, &ifr);
392*4d495c6eSApple OSS Distributions 	if (err != 0) {
393*4d495c6eSApple OSS Distributions 		this_errno = errno;
394*4d495c6eSApple OSS Distributions 		T_LOG("SIOCSIFLLADDR %s %s (%d)", ifname,
395*4d495c6eSApple OSS Distributions 		    strerror(this_errno), this_errno);
396*4d495c6eSApple OSS Distributions 	} else {
397*4d495c6eSApple OSS Distributions 		T_LOG("SIOCSIFLLADDR %s success", ifname);
398*4d495c6eSApple OSS Distributions 	}
399*4d495c6eSApple OSS Distributions 	return err;
400*4d495c6eSApple OSS Distributions }
401*4d495c6eSApple OSS Distributions 
402*4d495c6eSApple OSS Distributions 
403*4d495c6eSApple OSS Distributions void
ifnet_attach_ip(char * name)404*4d495c6eSApple OSS Distributions ifnet_attach_ip(char * name)
405*4d495c6eSApple OSS Distributions {
406*4d495c6eSApple OSS Distributions 	int             err;
407*4d495c6eSApple OSS Distributions 	struct ifreq    ifr;
408*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
409*4d495c6eSApple OSS Distributions 
410*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
411*4d495c6eSApple OSS Distributions 	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
412*4d495c6eSApple OSS Distributions 	err = ioctl(s, SIOCPROTOATTACH, &ifr);
413*4d495c6eSApple OSS Distributions 	T_QUIET;
414*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTOATTACH %s", ifr.ifr_name);
415*4d495c6eSApple OSS Distributions 	return;
416*4d495c6eSApple OSS Distributions }
417*4d495c6eSApple OSS Distributions 
418*4d495c6eSApple OSS Distributions void
ifnet_start_ipv6(const char * ifname)419*4d495c6eSApple OSS Distributions ifnet_start_ipv6(const char * ifname)
420*4d495c6eSApple OSS Distributions {
421*4d495c6eSApple OSS Distributions 	int             s6 = inet6_dgram_socket_get();
422*4d495c6eSApple OSS Distributions 
423*4d495c6eSApple OSS Distributions 	/* attach IPv6 */
424*4d495c6eSApple OSS Distributions 	siocprotoattach_in6(s6, ifname);
425*4d495c6eSApple OSS Distributions 
426*4d495c6eSApple OSS Distributions 	/* disable DAD to avoid 1 second delay (rdar://problem/73270401) */
427*4d495c6eSApple OSS Distributions 	nd_flags_set(s6, ifname, 0, ND6_IFF_DAD);
428*4d495c6eSApple OSS Distributions 
429*4d495c6eSApple OSS Distributions 	/* start IPv6LL */
430*4d495c6eSApple OSS Distributions 	siocll_start(s6, ifname);
431*4d495c6eSApple OSS Distributions 
432*4d495c6eSApple OSS Distributions 	return;
433*4d495c6eSApple OSS Distributions }
434*4d495c6eSApple OSS Distributions 
435*4d495c6eSApple OSS Distributions int
ifnet_destroy(const char * ifname,bool fail_on_error)436*4d495c6eSApple OSS Distributions ifnet_destroy(const char * ifname, bool fail_on_error)
437*4d495c6eSApple OSS Distributions {
438*4d495c6eSApple OSS Distributions 	int             err;
439*4d495c6eSApple OSS Distributions 	struct ifreq    ifr;
440*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
441*4d495c6eSApple OSS Distributions 
442*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
443*4d495c6eSApple OSS Distributions 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
444*4d495c6eSApple OSS Distributions 	err = ioctl(s, SIOCIFDESTROY, &ifr);
445*4d495c6eSApple OSS Distributions 	if (fail_on_error) {
446*4d495c6eSApple OSS Distributions 		T_QUIET;
447*4d495c6eSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
448*4d495c6eSApple OSS Distributions 	}
449*4d495c6eSApple OSS Distributions 	if (err < 0) {
450*4d495c6eSApple OSS Distributions 		T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
451*4d495c6eSApple OSS Distributions 	}
452*4d495c6eSApple OSS Distributions 	return err;
453*4d495c6eSApple OSS Distributions }
454*4d495c6eSApple OSS Distributions 
455*4d495c6eSApple OSS Distributions int
ifnet_set_flags(const char * ifname,uint16_t flags_set,uint16_t flags_clear)456*4d495c6eSApple OSS Distributions ifnet_set_flags(const char * ifname, uint16_t flags_set, uint16_t flags_clear)
457*4d495c6eSApple OSS Distributions {
458*4d495c6eSApple OSS Distributions 	uint16_t        flags_after;
459*4d495c6eSApple OSS Distributions 	uint16_t        flags_before;
460*4d495c6eSApple OSS Distributions 	struct ifreq    ifr;
461*4d495c6eSApple OSS Distributions 	int             ret;
462*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
463*4d495c6eSApple OSS Distributions 
464*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
465*4d495c6eSApple OSS Distributions 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
466*4d495c6eSApple OSS Distributions 	ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
467*4d495c6eSApple OSS Distributions 	if (ret != 0) {
468*4d495c6eSApple OSS Distributions 		T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
469*4d495c6eSApple OSS Distributions 		return ret;
470*4d495c6eSApple OSS Distributions 	}
471*4d495c6eSApple OSS Distributions 	flags_before = (uint16_t)ifr.ifr_flags;
472*4d495c6eSApple OSS Distributions 	ifr.ifr_flags |= flags_set;
473*4d495c6eSApple OSS Distributions 	ifr.ifr_flags &= ~(flags_clear);
474*4d495c6eSApple OSS Distributions 	flags_after = (uint16_t)ifr.ifr_flags;
475*4d495c6eSApple OSS Distributions 	if (flags_before == flags_after) {
476*4d495c6eSApple OSS Distributions 		/* nothing to do */
477*4d495c6eSApple OSS Distributions 		ret = 0;
478*4d495c6eSApple OSS Distributions 	} else {
479*4d495c6eSApple OSS Distributions 		/* issue the ioctl */
480*4d495c6eSApple OSS Distributions 		T_QUIET;
481*4d495c6eSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
482*4d495c6eSApple OSS Distributions 		    "SIOCSIFFLAGS %s 0x%x",
483*4d495c6eSApple OSS Distributions 		    ifr.ifr_name, (uint16_t)ifr.ifr_flags);
484*4d495c6eSApple OSS Distributions 		if (G_debug) {
485*4d495c6eSApple OSS Distributions 			T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
486*4d495c6eSApple OSS Distributions 			    ifr.ifr_name, flags_set, flags_clear,
487*4d495c6eSApple OSS Distributions 			    flags_before, flags_after);
488*4d495c6eSApple OSS Distributions 		}
489*4d495c6eSApple OSS Distributions 	}
490*4d495c6eSApple OSS Distributions 	return ret;
491*4d495c6eSApple OSS Distributions }
492*4d495c6eSApple OSS Distributions 
493*4d495c6eSApple OSS Distributions /* On some platforms with DEBUG kernel, we need to wait a while */
494*4d495c6eSApple OSS Distributions #define SIFCREATE_RETRY 600
495*4d495c6eSApple OSS Distributions 
496*4d495c6eSApple OSS Distributions static int
ifnet_create_common(const char * ifname,char * ifname_out,size_t ifname_out_len)497*4d495c6eSApple OSS Distributions ifnet_create_common(const char * ifname, char *ifname_out, size_t ifname_out_len)
498*4d495c6eSApple OSS Distributions {
499*4d495c6eSApple OSS Distributions 	int             error = 0;
500*4d495c6eSApple OSS Distributions 	struct ifreq    ifr;
501*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
502*4d495c6eSApple OSS Distributions 
503*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
504*4d495c6eSApple OSS Distributions 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
505*4d495c6eSApple OSS Distributions 
506*4d495c6eSApple OSS Distributions 	for (int i = 0; i < SIFCREATE_RETRY; i++) {
507*4d495c6eSApple OSS Distributions 		if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
508*4d495c6eSApple OSS Distributions 			error = errno;
509*4d495c6eSApple OSS Distributions 			T_LOG("SIOCSIFCREATE %s: %s", ifname,
510*4d495c6eSApple OSS Distributions 			    strerror(error));
511*4d495c6eSApple OSS Distributions 			if (error == EBUSY) {
512*4d495c6eSApple OSS Distributions 				/* interface is tearing down, try again */
513*4d495c6eSApple OSS Distributions 				usleep(10000);
514*4d495c6eSApple OSS Distributions 			} else if (error == EEXIST) {
515*4d495c6eSApple OSS Distributions 				/* interface exists, try destroying it */
516*4d495c6eSApple OSS Distributions 				(void)ifnet_destroy(ifname, false);
517*4d495c6eSApple OSS Distributions 			} else {
518*4d495c6eSApple OSS Distributions 				/* unexpected failure */
519*4d495c6eSApple OSS Distributions 				break;
520*4d495c6eSApple OSS Distributions 			}
521*4d495c6eSApple OSS Distributions 		} else {
522*4d495c6eSApple OSS Distributions 			if (ifname_out != NULL) {
523*4d495c6eSApple OSS Distributions 				strlcpy(ifname_out, ifr.ifr_name, ifname_out_len);
524*4d495c6eSApple OSS Distributions 			}
525*4d495c6eSApple OSS Distributions 			error = 0;
526*4d495c6eSApple OSS Distributions 			break;
527*4d495c6eSApple OSS Distributions 		}
528*4d495c6eSApple OSS Distributions 	}
529*4d495c6eSApple OSS Distributions 	if (error == 0) {
530*4d495c6eSApple OSS Distributions 		error = ifnet_set_flags(ifname, IFF_UP, 0);
531*4d495c6eSApple OSS Distributions 	}
532*4d495c6eSApple OSS Distributions 	return error;
533*4d495c6eSApple OSS Distributions }
534*4d495c6eSApple OSS Distributions 
535*4d495c6eSApple OSS Distributions int
ifnet_create(const char * ifname)536*4d495c6eSApple OSS Distributions ifnet_create(const char * ifname)
537*4d495c6eSApple OSS Distributions {
538*4d495c6eSApple OSS Distributions 	return ifnet_create_common(ifname, NULL, 0);
539*4d495c6eSApple OSS Distributions }
540*4d495c6eSApple OSS Distributions 
541*4d495c6eSApple OSS Distributions int
ifnet_create_2(char * ifname,size_t len)542*4d495c6eSApple OSS Distributions ifnet_create_2(char * ifname, size_t len)
543*4d495c6eSApple OSS Distributions {
544*4d495c6eSApple OSS Distributions 	return ifnet_create_common(ifname, ifname, len);
545*4d495c6eSApple OSS Distributions }
546*4d495c6eSApple OSS Distributions 
547*4d495c6eSApple OSS Distributions void
ifnet_add_ip_address(char * ifname,struct in_addr addr,struct in_addr mask)548*4d495c6eSApple OSS Distributions ifnet_add_ip_address(char *ifname, struct in_addr addr, struct in_addr mask)
549*4d495c6eSApple OSS Distributions {
550*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
551*4d495c6eSApple OSS Distributions 
552*4d495c6eSApple OSS Distributions 	siocaifaddr(s, ifname, addr, mask);
553*4d495c6eSApple OSS Distributions }
554*4d495c6eSApple OSS Distributions 
555*4d495c6eSApple OSS Distributions void
ifnet_remove_ip_address(char * ifname,struct in_addr addr,struct in_addr mask)556*4d495c6eSApple OSS Distributions ifnet_remove_ip_address(char *ifname, struct in_addr addr, struct in_addr mask)
557*4d495c6eSApple OSS Distributions {
558*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
559*4d495c6eSApple OSS Distributions 
560*4d495c6eSApple OSS Distributions 	siocdifaddr(s, ifname, addr, mask);
561*4d495c6eSApple OSS Distributions }
562*4d495c6eSApple OSS Distributions 
563*4d495c6eSApple OSS Distributions int
ifnet_set_mtu(const char * ifname,int mtu)564*4d495c6eSApple OSS Distributions ifnet_set_mtu(const char *ifname, int mtu)
565*4d495c6eSApple OSS Distributions {
566*4d495c6eSApple OSS Distributions 	int error = 0;
567*4d495c6eSApple OSS Distributions 	struct ifreq ifr = { 0 };
568*4d495c6eSApple OSS Distributions 	int s = inet_dgram_socket_get();
569*4d495c6eSApple OSS Distributions 
570*4d495c6eSApple OSS Distributions 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
571*4d495c6eSApple OSS Distributions 	ifr.ifr_mtu = mtu;
572*4d495c6eSApple OSS Distributions 
573*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFMTU, (caddr_t)&ifr), "set MTU");
574*4d495c6eSApple OSS Distributions 
575*4d495c6eSApple OSS Distributions 	return error;
576*4d495c6eSApple OSS Distributions }
577*4d495c6eSApple OSS Distributions 
578*4d495c6eSApple OSS Distributions int
siocdrvspec(const char * ifname,u_long op,void * arg,size_t argsize,bool set)579*4d495c6eSApple OSS Distributions siocdrvspec(const char * ifname, u_long op, void *arg, size_t argsize, bool set)
580*4d495c6eSApple OSS Distributions {
581*4d495c6eSApple OSS Distributions 	struct ifdrv    ifd;
582*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
583*4d495c6eSApple OSS Distributions 
584*4d495c6eSApple OSS Distributions 	memset(&ifd, 0, sizeof(ifd));
585*4d495c6eSApple OSS Distributions 	strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
586*4d495c6eSApple OSS Distributions 	ifd.ifd_cmd = op;
587*4d495c6eSApple OSS Distributions 	ifd.ifd_len = argsize;
588*4d495c6eSApple OSS Distributions 	ifd.ifd_data = arg;
589*4d495c6eSApple OSS Distributions 	return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
590*4d495c6eSApple OSS Distributions }
591*4d495c6eSApple OSS Distributions 
592*4d495c6eSApple OSS Distributions void
fake_set_peer(const char * feth,const char * feth_peer)593*4d495c6eSApple OSS Distributions fake_set_peer(const char * feth, const char * feth_peer)
594*4d495c6eSApple OSS Distributions {
595*4d495c6eSApple OSS Distributions 	struct if_fake_request  iffr;
596*4d495c6eSApple OSS Distributions 	int                     ret;
597*4d495c6eSApple OSS Distributions 
598*4d495c6eSApple OSS Distributions 	bzero((char *)&iffr, sizeof(iffr));
599*4d495c6eSApple OSS Distributions 	if (feth_peer != NULL) {
600*4d495c6eSApple OSS Distributions 		strlcpy(iffr.iffr_peer_name, feth_peer,
601*4d495c6eSApple OSS Distributions 		    sizeof(iffr.iffr_peer_name));
602*4d495c6eSApple OSS Distributions 	}
603*4d495c6eSApple OSS Distributions 	ret = siocdrvspec(feth, IF_FAKE_S_CMD_SET_PEER,
604*4d495c6eSApple OSS Distributions 	    &iffr, sizeof(iffr), true);
605*4d495c6eSApple OSS Distributions 	T_QUIET;
606*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret,
607*4d495c6eSApple OSS Distributions 	    "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
608*4d495c6eSApple OSS Distributions 	    feth, (feth_peer != NULL) ? feth_peer : "<none>");
609*4d495c6eSApple OSS Distributions 	T_LOG("%s peer %s\n", feth, feth_peer);
610*4d495c6eSApple OSS Distributions 	return;
611*4d495c6eSApple OSS Distributions }
612*4d495c6eSApple OSS Distributions 
613*4d495c6eSApple OSS Distributions void
siocsifvlan(const char * vlan,const char * phys,uint16_t tag)614*4d495c6eSApple OSS Distributions siocsifvlan(const char * vlan, const char * phys, uint16_t tag)
615*4d495c6eSApple OSS Distributions {
616*4d495c6eSApple OSS Distributions 	int             result;
617*4d495c6eSApple OSS Distributions 	struct ifreq    ifr;
618*4d495c6eSApple OSS Distributions 	int             s = inet_dgram_socket_get();
619*4d495c6eSApple OSS Distributions 	struct vlanreq  vlr;
620*4d495c6eSApple OSS Distributions 
621*4d495c6eSApple OSS Distributions 	bzero(&ifr, sizeof(ifr));
622*4d495c6eSApple OSS Distributions 	strlcpy(ifr.ifr_name, vlan, sizeof(ifr.ifr_name));
623*4d495c6eSApple OSS Distributions 	ifr.ifr_data = (caddr_t)&vlr;
624*4d495c6eSApple OSS Distributions 	strlcpy(vlr.vlr_parent, phys, sizeof(vlr.vlr_parent));
625*4d495c6eSApple OSS Distributions 	vlr.vlr_tag = tag;
626*4d495c6eSApple OSS Distributions 	result = ioctl(s, SIOCSIFVLAN, &ifr);
627*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(result, "SIOCSIFVLAN(%s) %s %d",
628*4d495c6eSApple OSS Distributions 	    vlan, phys, tag);
629*4d495c6eSApple OSS Distributions }
630*4d495c6eSApple OSS Distributions 
631*4d495c6eSApple OSS Distributions u_int
make_dhcp_payload(dhcp_min_payload_t payload,ether_addr_t * eaddr)632*4d495c6eSApple OSS Distributions make_dhcp_payload(dhcp_min_payload_t payload, ether_addr_t *eaddr)
633*4d495c6eSApple OSS Distributions {
634*4d495c6eSApple OSS Distributions 	struct bootp *  dhcp;
635*4d495c6eSApple OSS Distributions 	u_int           payload_length;
636*4d495c6eSApple OSS Distributions 
637*4d495c6eSApple OSS Distributions 	/* create a minimal BOOTP packet */
638*4d495c6eSApple OSS Distributions 	payload_length = sizeof(*payload);
639*4d495c6eSApple OSS Distributions 	dhcp = (struct bootp *)payload;
640*4d495c6eSApple OSS Distributions 	bzero(dhcp, payload_length);
641*4d495c6eSApple OSS Distributions 	dhcp->bp_op = BOOTREQUEST;
642*4d495c6eSApple OSS Distributions 	dhcp->bp_htype = ARPHRD_ETHER;
643*4d495c6eSApple OSS Distributions 	dhcp->bp_hlen = sizeof(*eaddr);
644*4d495c6eSApple OSS Distributions 	bcopy(eaddr->octet, dhcp->bp_chaddr, sizeof(eaddr->octet));
645*4d495c6eSApple OSS Distributions 	return payload_length;
646*4d495c6eSApple OSS Distributions }
647*4d495c6eSApple OSS Distributions 
648*4d495c6eSApple OSS Distributions 
649*4d495c6eSApple OSS Distributions 
650*4d495c6eSApple OSS Distributions /*
651*4d495c6eSApple OSS Distributions  * routing table
652*4d495c6eSApple OSS Distributions  */
653*4d495c6eSApple OSS Distributions 
654*4d495c6eSApple OSS Distributions /*
655*4d495c6eSApple OSS Distributions  * Stolen/modified from IPMonitor/ip_plugin.c
656*4d495c6eSApple OSS Distributions  */
657*4d495c6eSApple OSS Distributions /*
658*4d495c6eSApple OSS Distributions  * Define: ROUTE_MSG_ADDRS_SPACE
659*4d495c6eSApple OSS Distributions  * Purpose:
660*4d495c6eSApple OSS Distributions  *   Since sizeof(sockaddr_dl) > sizeof(sockaddr_in), we need space for
661*4d495c6eSApple OSS Distributions  *   3 sockaddr_in's and 2 sockaddr_dl's, but pad it just in case
662*4d495c6eSApple OSS Distributions  *   someone changes the code and doesn't think to modify this.
663*4d495c6eSApple OSS Distributions  */
664*4d495c6eSApple OSS Distributions #define ROUTE_MSG_ADDRS_SPACE   (3 * sizeof(struct sockaddr_in) \
665*4d495c6eSApple OSS Distributions 	                         + 2 * sizeof(struct sockaddr_dl) \
666*4d495c6eSApple OSS Distributions 	                         + 128)
667*4d495c6eSApple OSS Distributions typedef struct {
668*4d495c6eSApple OSS Distributions 	struct rt_msghdr    hdr;
669*4d495c6eSApple OSS Distributions 	char                addrs[ROUTE_MSG_ADDRS_SPACE];
670*4d495c6eSApple OSS Distributions } route_msg;
671*4d495c6eSApple OSS Distributions 
672*4d495c6eSApple OSS Distributions typedef unsigned short  IFIndex;
673*4d495c6eSApple OSS Distributions 
674*4d495c6eSApple OSS Distributions typedef enum {
675*4d495c6eSApple OSS Distributions 	kRouteFlagsIsScoped         = 0x0001,
676*4d495c6eSApple OSS Distributions 	kRouteFlagsHasGateway       = 0x0002,
677*4d495c6eSApple OSS Distributions 	kRouteFlagsIsHost           = 0x0004,
678*4d495c6eSApple OSS Distributions } RouteFlags;
679*4d495c6eSApple OSS Distributions 
680*4d495c6eSApple OSS Distributions typedef struct {
681*4d495c6eSApple OSS Distributions 	IFIndex         ifindex;
682*4d495c6eSApple OSS Distributions 	RouteFlags      flags;
683*4d495c6eSApple OSS Distributions 	struct in_addr  dest;
684*4d495c6eSApple OSS Distributions 	struct in_addr  mask;
685*4d495c6eSApple OSS Distributions 	struct in_addr  gateway;
686*4d495c6eSApple OSS Distributions 	struct in_addr  ifa;
687*4d495c6eSApple OSS Distributions } IPv4Route, * IPv4RouteRef;
688*4d495c6eSApple OSS Distributions 
689*4d495c6eSApple OSS Distributions /*
690*4d495c6eSApple OSS Distributions  * Function: IPv4RouteApply
691*4d495c6eSApple OSS Distributions  * Purpose:
692*4d495c6eSApple OSS Distributions  *   Add or remove the specified route to/from the kernel routing table.
693*4d495c6eSApple OSS Distributions  */
694*4d495c6eSApple OSS Distributions static int
IPv4RouteApply(IPv4RouteRef route,uint8_t cmd,int s)695*4d495c6eSApple OSS Distributions IPv4RouteApply(IPv4RouteRef route, uint8_t cmd, int s)
696*4d495c6eSApple OSS Distributions {
697*4d495c6eSApple OSS Distributions 	size_t          len;
698*4d495c6eSApple OSS Distributions 	int             ret = 0;
699*4d495c6eSApple OSS Distributions 	route_msg       rtmsg;
700*4d495c6eSApple OSS Distributions 	union {
701*4d495c6eSApple OSS Distributions 		struct sockaddr_in *    in_p;
702*4d495c6eSApple OSS Distributions 		struct sockaddr_dl *    dl_p;
703*4d495c6eSApple OSS Distributions 		char *                  ptr;
704*4d495c6eSApple OSS Distributions 	} rtaddr;
705*4d495c6eSApple OSS Distributions 	static int      rtm_seq;
706*4d495c6eSApple OSS Distributions 	static bool     rtm_seq_inited;
707*4d495c6eSApple OSS Distributions 
708*4d495c6eSApple OSS Distributions 	if (!rtm_seq_inited) {
709*4d495c6eSApple OSS Distributions 		rtm_seq_inited = true;
710*4d495c6eSApple OSS Distributions 		rtm_seq = (int)arc4random();
711*4d495c6eSApple OSS Distributions 	}
712*4d495c6eSApple OSS Distributions 	if (route->ifindex == 0) {
713*4d495c6eSApple OSS Distributions 		T_LOG("no interface specified, ignoring %s",
714*4d495c6eSApple OSS Distributions 		    inet_ntoa(route->dest));
715*4d495c6eSApple OSS Distributions 		return ENXIO;
716*4d495c6eSApple OSS Distributions 	}
717*4d495c6eSApple OSS Distributions 	if (s < 0) {
718*4d495c6eSApple OSS Distributions 		T_LOG("invalid routing socket");
719*4d495c6eSApple OSS Distributions 		return EBADF;
720*4d495c6eSApple OSS Distributions 	}
721*4d495c6eSApple OSS Distributions 	memset(&rtmsg, 0, sizeof(rtmsg));
722*4d495c6eSApple OSS Distributions 	rtmsg.hdr.rtm_type = cmd;
723*4d495c6eSApple OSS Distributions 	rtmsg.hdr.rtm_version = RTM_VERSION;
724*4d495c6eSApple OSS Distributions 	rtmsg.hdr.rtm_seq = rtm_seq++;
725*4d495c6eSApple OSS Distributions 	rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP;
726*4d495c6eSApple OSS Distributions 	if (route->ifa.s_addr != 0) {
727*4d495c6eSApple OSS Distributions 		rtmsg.hdr.rtm_addrs |= RTA_IFA;
728*4d495c6eSApple OSS Distributions 	}
729*4d495c6eSApple OSS Distributions 	rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
730*4d495c6eSApple OSS Distributions 	if ((route->flags & kRouteFlagsIsHost) != 0) {
731*4d495c6eSApple OSS Distributions 		rtmsg.hdr.rtm_flags |= RTF_HOST;
732*4d495c6eSApple OSS Distributions 	} else {
733*4d495c6eSApple OSS Distributions 		rtmsg.hdr.rtm_addrs |= RTA_NETMASK;
734*4d495c6eSApple OSS Distributions 		if ((route->flags & kRouteFlagsHasGateway) == 0) {
735*4d495c6eSApple OSS Distributions 			rtmsg.hdr.rtm_flags |= RTF_CLONING;
736*4d495c6eSApple OSS Distributions 		}
737*4d495c6eSApple OSS Distributions 	}
738*4d495c6eSApple OSS Distributions 	if ((route->flags & kRouteFlagsHasGateway) != 0) {
739*4d495c6eSApple OSS Distributions 		rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
740*4d495c6eSApple OSS Distributions 	}
741*4d495c6eSApple OSS Distributions 	if ((route->flags & kRouteFlagsIsScoped) != 0) {
742*4d495c6eSApple OSS Distributions 		rtmsg.hdr.rtm_index = route->ifindex;
743*4d495c6eSApple OSS Distributions 		rtmsg.hdr.rtm_flags |= RTF_IFSCOPE;
744*4d495c6eSApple OSS Distributions 	}
745*4d495c6eSApple OSS Distributions 
746*4d495c6eSApple OSS Distributions 	rtaddr.ptr = rtmsg.addrs;
747*4d495c6eSApple OSS Distributions 
748*4d495c6eSApple OSS Distributions 	/* dest */
749*4d495c6eSApple OSS Distributions 	rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
750*4d495c6eSApple OSS Distributions 	rtaddr.in_p->sin_family = AF_INET;
751*4d495c6eSApple OSS Distributions 	rtaddr.in_p->sin_addr = route->dest;
752*4d495c6eSApple OSS Distributions 	rtaddr.ptr += sizeof(*rtaddr.in_p);
753*4d495c6eSApple OSS Distributions 
754*4d495c6eSApple OSS Distributions 	/* gateway */
755*4d495c6eSApple OSS Distributions 	if ((rtmsg.hdr.rtm_flags & RTF_GATEWAY) != 0) {
756*4d495c6eSApple OSS Distributions 		/* gateway is an IP address */
757*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
758*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_family = AF_INET;
759*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_addr = route->gateway;
760*4d495c6eSApple OSS Distributions 		rtaddr.ptr += sizeof(*rtaddr.in_p);
761*4d495c6eSApple OSS Distributions 	} else {
762*4d495c6eSApple OSS Distributions 		/* gateway is the interface itself */
763*4d495c6eSApple OSS Distributions 		rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
764*4d495c6eSApple OSS Distributions 		rtaddr.dl_p->sdl_family = AF_LINK;
765*4d495c6eSApple OSS Distributions 		rtaddr.dl_p->sdl_index = route->ifindex;
766*4d495c6eSApple OSS Distributions 		rtaddr.ptr += sizeof(*rtaddr.dl_p);
767*4d495c6eSApple OSS Distributions 	}
768*4d495c6eSApple OSS Distributions 
769*4d495c6eSApple OSS Distributions 	/* mask */
770*4d495c6eSApple OSS Distributions 	if ((rtmsg.hdr.rtm_addrs & RTA_NETMASK) != 0) {
771*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
772*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_family = AF_INET;
773*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_addr = route->mask;
774*4d495c6eSApple OSS Distributions 		rtaddr.ptr += sizeof(*rtaddr.in_p);
775*4d495c6eSApple OSS Distributions 	}
776*4d495c6eSApple OSS Distributions 
777*4d495c6eSApple OSS Distributions 	/* interface */
778*4d495c6eSApple OSS Distributions 	if ((rtmsg.hdr.rtm_addrs & RTA_IFP) != 0) {
779*4d495c6eSApple OSS Distributions 		rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
780*4d495c6eSApple OSS Distributions 		rtaddr.dl_p->sdl_family = AF_LINK;
781*4d495c6eSApple OSS Distributions 		rtaddr.dl_p->sdl_index = route->ifindex;
782*4d495c6eSApple OSS Distributions 		rtaddr.ptr += sizeof(*rtaddr.dl_p);
783*4d495c6eSApple OSS Distributions 	}
784*4d495c6eSApple OSS Distributions 	/* interface address */
785*4d495c6eSApple OSS Distributions 	if ((rtmsg.hdr.rtm_addrs & RTA_IFA) != 0) {
786*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
787*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_family = AF_INET;
788*4d495c6eSApple OSS Distributions 		rtaddr.in_p->sin_addr = route->ifa;
789*4d495c6eSApple OSS Distributions 		rtaddr.ptr += sizeof(*rtaddr.in_p);
790*4d495c6eSApple OSS Distributions 	}
791*4d495c6eSApple OSS Distributions 
792*4d495c6eSApple OSS Distributions 	/* apply the route */
793*4d495c6eSApple OSS Distributions 	len = (sizeof(rtmsg.hdr)
794*4d495c6eSApple OSS Distributions 	    + (unsigned long)(rtaddr.ptr - (char *)rtmsg.addrs));
795*4d495c6eSApple OSS Distributions 	rtmsg.hdr.rtm_msglen = (u_short)len;
796*4d495c6eSApple OSS Distributions 	if (write(s, &rtmsg, len) == -1) {
797*4d495c6eSApple OSS Distributions 		ret = errno;
798*4d495c6eSApple OSS Distributions 		T_LOG("write routing socket failed, (%d) %s",
799*4d495c6eSApple OSS Distributions 		    errno, strerror(errno));
800*4d495c6eSApple OSS Distributions 	}
801*4d495c6eSApple OSS Distributions 	return ret;
802*4d495c6eSApple OSS Distributions }
803*4d495c6eSApple OSS Distributions 
804*4d495c6eSApple OSS Distributions static int routing_socket = -1;
805*4d495c6eSApple OSS Distributions 
806*4d495c6eSApple OSS Distributions static int
routing_socket_get(void)807*4d495c6eSApple OSS Distributions routing_socket_get(void)
808*4d495c6eSApple OSS Distributions {
809*4d495c6eSApple OSS Distributions 	if (routing_socket != NO_SOCKET) {
810*4d495c6eSApple OSS Distributions 		goto done;
811*4d495c6eSApple OSS Distributions 	}
812*4d495c6eSApple OSS Distributions 	routing_socket = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE);
813*4d495c6eSApple OSS Distributions 	T_QUIET;
814*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(routing_socket,
815*4d495c6eSApple OSS Distributions 	    "socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)");
816*4d495c6eSApple OSS Distributions done:
817*4d495c6eSApple OSS Distributions 	return routing_socket;
818*4d495c6eSApple OSS Distributions }
819*4d495c6eSApple OSS Distributions 
820*4d495c6eSApple OSS Distributions void
route_add_inet_scoped_subnet(char * ifname,u_short if_index,struct in_addr ifa,struct in_addr mask)821*4d495c6eSApple OSS Distributions route_add_inet_scoped_subnet(char * ifname, u_short if_index,
822*4d495c6eSApple OSS Distributions     struct in_addr ifa, struct in_addr mask)
823*4d495c6eSApple OSS Distributions {
824*4d495c6eSApple OSS Distributions 	int             error;
825*4d495c6eSApple OSS Distributions 	IPv4Route       route;
826*4d495c6eSApple OSS Distributions 	int             rs = routing_socket_get();
827*4d495c6eSApple OSS Distributions 
828*4d495c6eSApple OSS Distributions 	bzero(&route, sizeof(route));
829*4d495c6eSApple OSS Distributions 	route.flags |= kRouteFlagsIsScoped;
830*4d495c6eSApple OSS Distributions 	route.ifa = ifa;
831*4d495c6eSApple OSS Distributions 	route.ifindex = if_index;
832*4d495c6eSApple OSS Distributions 	route.mask = mask;
833*4d495c6eSApple OSS Distributions 	route.dest.s_addr = route.ifa.s_addr & route.mask.s_addr;
834*4d495c6eSApple OSS Distributions 	T_QUIET;
835*4d495c6eSApple OSS Distributions 	T_ASSERT_NE((int)route.ifindex, 0, "if_nametoindex(%s)", ifname);
836*4d495c6eSApple OSS Distributions 	error = IPv4RouteApply(&route, RTM_ADD, rs);
837*4d495c6eSApple OSS Distributions 	T_ASSERT_EQ(error, 0, "add scoped subnet route %s %s/24", ifname,
838*4d495c6eSApple OSS Distributions 	    inet_ntoa(route.dest));
839*4d495c6eSApple OSS Distributions 	return;
840*4d495c6eSApple OSS Distributions }
841*4d495c6eSApple OSS Distributions 
842*4d495c6eSApple OSS Distributions /**
843*4d495c6eSApple OSS Distributions ** network_interface
844*4d495c6eSApple OSS Distributions **/
845*4d495c6eSApple OSS Distributions 
846*4d495c6eSApple OSS Distributions void
network_interface_create(network_interface_t if_p,const if_name_t name)847*4d495c6eSApple OSS Distributions network_interface_create(network_interface_t if_p, const if_name_t name)
848*4d495c6eSApple OSS Distributions {
849*4d495c6eSApple OSS Distributions 	int             error;
850*4d495c6eSApple OSS Distributions 	size_t          len = sizeof(if_p->if_name);
851*4d495c6eSApple OSS Distributions 
852*4d495c6eSApple OSS Distributions 	strlcpy(if_p->if_name, name, len);
853*4d495c6eSApple OSS Distributions 	error = ifnet_create_2(if_p->if_name, len);
854*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(error, "ifnet_create_2 %s", if_p->if_name);
855*4d495c6eSApple OSS Distributions 
856*4d495c6eSApple OSS Distributions 	if_p->if_index = (u_short)if_nametoindex(if_p->if_name);
857*4d495c6eSApple OSS Distributions 	T_QUIET;
858*4d495c6eSApple OSS Distributions 	T_ASSERT_TRUE(if_p->if_index != 0, NULL);
859*4d495c6eSApple OSS Distributions 	T_LOG("%s: created %s index %d\n",
860*4d495c6eSApple OSS Distributions 	    __func__, if_p->if_name, if_p->if_index);
861*4d495c6eSApple OSS Distributions }
862*4d495c6eSApple OSS Distributions 
863*4d495c6eSApple OSS Distributions void
network_interface_destroy(network_interface_t if_p)864*4d495c6eSApple OSS Distributions network_interface_destroy(network_interface_t if_p)
865*4d495c6eSApple OSS Distributions {
866*4d495c6eSApple OSS Distributions 	if (if_p->if_index != 0) {
867*4d495c6eSApple OSS Distributions 		ifnet_destroy(if_p->if_name, false);
868*4d495c6eSApple OSS Distributions 		T_LOG("%s: destroyed %s\n", __func__, if_p->if_name);
869*4d495c6eSApple OSS Distributions 	}
870*4d495c6eSApple OSS Distributions }
871*4d495c6eSApple OSS Distributions 
872*4d495c6eSApple OSS Distributions static inline size_t
network_interface_pair_list_size(size_t count)873*4d495c6eSApple OSS Distributions network_interface_pair_list_size(size_t count)
874*4d495c6eSApple OSS Distributions {
875*4d495c6eSApple OSS Distributions 	return offsetof(network_interface_pair_list, list[count]);
876*4d495c6eSApple OSS Distributions }
877*4d495c6eSApple OSS Distributions 
878*4d495c6eSApple OSS Distributions network_interface_pair_list_t
network_interface_pair_list_alloc(u_int n)879*4d495c6eSApple OSS Distributions network_interface_pair_list_alloc(u_int n)
880*4d495c6eSApple OSS Distributions {
881*4d495c6eSApple OSS Distributions 	network_interface_pair_list_t   list;
882*4d495c6eSApple OSS Distributions 
883*4d495c6eSApple OSS Distributions 	list = (network_interface_pair_list_t)
884*4d495c6eSApple OSS Distributions 	    calloc(1, network_interface_pair_list_size(n));
885*4d495c6eSApple OSS Distributions 	list->count = n;
886*4d495c6eSApple OSS Distributions 	return list;
887*4d495c6eSApple OSS Distributions }
888*4d495c6eSApple OSS Distributions 
889*4d495c6eSApple OSS Distributions void
network_interface_pair_list_destroy(network_interface_pair_list_t list)890*4d495c6eSApple OSS Distributions network_interface_pair_list_destroy(network_interface_pair_list_t list)
891*4d495c6eSApple OSS Distributions {
892*4d495c6eSApple OSS Distributions 	network_interface_pair_t        scan;
893*4d495c6eSApple OSS Distributions 
894*4d495c6eSApple OSS Distributions 	if (list == NULL) {
895*4d495c6eSApple OSS Distributions 		return;
896*4d495c6eSApple OSS Distributions 	}
897*4d495c6eSApple OSS Distributions 	scan = list->list;
898*4d495c6eSApple OSS Distributions 	for (size_t i = 0; i < list->count; i++, scan++) {
899*4d495c6eSApple OSS Distributions 		network_interface_destroy(&scan->one);
900*4d495c6eSApple OSS Distributions 		network_interface_destroy(&scan->two);
901*4d495c6eSApple OSS Distributions 	}
902*4d495c6eSApple OSS Distributions }
903*4d495c6eSApple OSS Distributions 
904*4d495c6eSApple OSS Distributions bool
has_ipv4_default_route(void)905*4d495c6eSApple OSS Distributions has_ipv4_default_route(void)
906*4d495c6eSApple OSS Distributions {
907*4d495c6eSApple OSS Distributions 	bool result = false;
908*4d495c6eSApple OSS Distributions 	struct rt_msghdr *rtm = NULL;
909*4d495c6eSApple OSS Distributions 	struct sockaddr_in sin = { 0 };
910*4d495c6eSApple OSS Distributions 
911*4d495c6eSApple OSS Distributions 	sin.sin_len = sizeof(struct sockaddr_in);
912*4d495c6eSApple OSS Distributions 	sin.sin_family = AF_INET;
913*4d495c6eSApple OSS Distributions 	sin.sin_addr.s_addr = INADDR_ANY;
914*4d495c6eSApple OSS Distributions 
915*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(rtm = (struct rt_msghdr *)calloc(1, RTM_BUFLEN), NULL);
916*4d495c6eSApple OSS Distributions 
917*4d495c6eSApple OSS Distributions 	rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
918*4d495c6eSApple OSS Distributions 	rtm->rtm_version = RTM_VERSION;
919*4d495c6eSApple OSS Distributions 	rtm->rtm_type = RTM_GET;
920*4d495c6eSApple OSS Distributions 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY | RTF_HOST;
921*4d495c6eSApple OSS Distributions 	rtm->rtm_addrs = RTA_DST;
922*4d495c6eSApple OSS Distributions 	rtm->rtm_pid = getpid();
923*4d495c6eSApple OSS Distributions 	rtm->rtm_seq = 1;
924*4d495c6eSApple OSS Distributions 
925*4d495c6eSApple OSS Distributions 	uint8_t *cp = (unsigned char *)(rtm + 1);
926*4d495c6eSApple OSS Distributions 
927*4d495c6eSApple OSS Distributions 	bcopy(&sin, cp, sin.sin_len);
928*4d495c6eSApple OSS Distributions 	cp += ROUNDUP(sin.sin_len);
929*4d495c6eSApple OSS Distributions 
930*4d495c6eSApple OSS Distributions 	u_short len = (u_short)(cp - (uint8_t *)rtm);
931*4d495c6eSApple OSS Distributions 
932*4d495c6eSApple OSS Distributions 	rtm->rtm_msglen = len;
933*4d495c6eSApple OSS Distributions 
934*4d495c6eSApple OSS Distributions 	int fd;
935*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(fd = socket(PF_ROUTE, SOCK_RAW, 0), NULL);
936*4d495c6eSApple OSS Distributions 
937*4d495c6eSApple OSS Distributions 	ssize_t sent = send(fd, rtm, len, 0);
938*4d495c6eSApple OSS Distributions 	if (sent == len) {
939*4d495c6eSApple OSS Distributions 		result = true;
940*4d495c6eSApple OSS Distributions 	} else {
941*4d495c6eSApple OSS Distributions 		result = false;
942*4d495c6eSApple OSS Distributions 	}
943*4d495c6eSApple OSS Distributions 
944*4d495c6eSApple OSS Distributions 	(void) close(fd);
945*4d495c6eSApple OSS Distributions 	free(rtm);
946*4d495c6eSApple OSS Distributions 
947*4d495c6eSApple OSS Distributions 	return result;
948*4d495c6eSApple OSS Distributions }
949*4d495c6eSApple OSS Distributions 
950*4d495c6eSApple OSS Distributions bool
has_ipv6_default_route(void)951*4d495c6eSApple OSS Distributions has_ipv6_default_route(void)
952*4d495c6eSApple OSS Distributions {
953*4d495c6eSApple OSS Distributions 	bool result = false;
954*4d495c6eSApple OSS Distributions 	struct rt_msghdr *rtm = NULL;
955*4d495c6eSApple OSS Distributions 	struct sockaddr_in6 sin6 = { 0 };
956*4d495c6eSApple OSS Distributions 
957*4d495c6eSApple OSS Distributions 	sin6.sin6_len = sizeof(struct sockaddr_in6);
958*4d495c6eSApple OSS Distributions 	sin6.sin6_family = AF_INET6;
959*4d495c6eSApple OSS Distributions 
960*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(rtm = (struct rt_msghdr *)calloc(1, RTM_BUFLEN), NULL);
961*4d495c6eSApple OSS Distributions 
962*4d495c6eSApple OSS Distributions 	rtm->rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in6);
963*4d495c6eSApple OSS Distributions 	rtm->rtm_version = RTM_VERSION;
964*4d495c6eSApple OSS Distributions 	rtm->rtm_type = RTM_GET;
965*4d495c6eSApple OSS Distributions 	rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY | RTF_HOST;
966*4d495c6eSApple OSS Distributions 	rtm->rtm_addrs = RTA_DST;
967*4d495c6eSApple OSS Distributions 	rtm->rtm_pid = getpid();
968*4d495c6eSApple OSS Distributions 	rtm->rtm_seq = 1;
969*4d495c6eSApple OSS Distributions 
970*4d495c6eSApple OSS Distributions 	uint8_t *cp = (unsigned char *)(rtm + 1);
971*4d495c6eSApple OSS Distributions 
972*4d495c6eSApple OSS Distributions 	bcopy(&sin6, cp, sin6.sin6_len);
973*4d495c6eSApple OSS Distributions 	cp += ROUNDUP(sin6.sin6_len);
974*4d495c6eSApple OSS Distributions 
975*4d495c6eSApple OSS Distributions 	u_short len = (u_short)(cp - (uint8_t *)rtm);
976*4d495c6eSApple OSS Distributions 
977*4d495c6eSApple OSS Distributions 	rtm->rtm_msglen = len;
978*4d495c6eSApple OSS Distributions 
979*4d495c6eSApple OSS Distributions 	int fd;
980*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(fd = socket(PF_ROUTE, SOCK_RAW, 0), NULL);
981*4d495c6eSApple OSS Distributions 
982*4d495c6eSApple OSS Distributions 	ssize_t sent = send(fd, rtm, len, 0);
983*4d495c6eSApple OSS Distributions 	if (sent == len) {
984*4d495c6eSApple OSS Distributions 		result = true;
985*4d495c6eSApple OSS Distributions 	} else {
986*4d495c6eSApple OSS Distributions 		result = false;
987*4d495c6eSApple OSS Distributions 	}
988*4d495c6eSApple OSS Distributions 
989*4d495c6eSApple OSS Distributions 	(void) close(fd);
990*4d495c6eSApple OSS Distributions 	free(rtm);
991*4d495c6eSApple OSS Distributions 
992*4d495c6eSApple OSS Distributions 	return result;
993*4d495c6eSApple OSS Distributions }
994*4d495c6eSApple OSS Distributions 
995*4d495c6eSApple OSS Distributions /*
996*4d495c6eSApple OSS Distributions  * Bridge management
997*4d495c6eSApple OSS Distributions  */
998*4d495c6eSApple OSS Distributions int
bridge_add_member(const char * bridge,const char * member)999*4d495c6eSApple OSS Distributions bridge_add_member(const char * bridge, const char * member)
1000*4d495c6eSApple OSS Distributions {
1001*4d495c6eSApple OSS Distributions 	struct ifbreq           req;
1002*4d495c6eSApple OSS Distributions 	int                     ret;
1003*4d495c6eSApple OSS Distributions 
1004*4d495c6eSApple OSS Distributions 	memset(&req, 0, sizeof(req));
1005*4d495c6eSApple OSS Distributions 	strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
1006*4d495c6eSApple OSS Distributions 	ret = siocdrvspec(bridge, BRDGADD, &req, sizeof(req), true);
1007*4d495c6eSApple OSS Distributions 	T_QUIET;
1008*4d495c6eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "%s %s %s", __func__, bridge, member);
1009*4d495c6eSApple OSS Distributions 	return ret;
1010*4d495c6eSApple OSS Distributions }
1011*4d495c6eSApple OSS Distributions 
1012*4d495c6eSApple OSS Distributions /*
1013*4d495c6eSApple OSS Distributions **  stolen from bootp/bootplib/util.c
1014*4d495c6eSApple OSS Distributions **
1015*4d495c6eSApple OSS Distributions **/
1016*4d495c6eSApple OSS Distributions 
1017*4d495c6eSApple OSS Distributions static int
rt_xaddrs(char * cp,const char * cplim,struct rt_addrinfo * rtinfo)1018*4d495c6eSApple OSS Distributions rt_xaddrs(char * cp, const char * cplim, struct rt_addrinfo * rtinfo)
1019*4d495c6eSApple OSS Distributions {
1020*4d495c6eSApple OSS Distributions 	int         i;
1021*4d495c6eSApple OSS Distributions 	struct sockaddr *   sa;
1022*4d495c6eSApple OSS Distributions 
1023*4d495c6eSApple OSS Distributions 	bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
1024*4d495c6eSApple OSS Distributions 	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
1025*4d495c6eSApple OSS Distributions 		if ((rtinfo->rti_addrs & (1 << i)) == 0) {
1026*4d495c6eSApple OSS Distributions 			continue;
1027*4d495c6eSApple OSS Distributions 		}
1028*4d495c6eSApple OSS Distributions 		sa = (struct sockaddr *)cp;
1029*4d495c6eSApple OSS Distributions 		if ((cp + sa->sa_len) > cplim) {
1030*4d495c6eSApple OSS Distributions 			return EINVAL;
1031*4d495c6eSApple OSS Distributions 		}
1032*4d495c6eSApple OSS Distributions 		rtinfo->rti_info[i] = sa;
1033*4d495c6eSApple OSS Distributions 		cp += ROUNDUP(sa->sa_len);
1034*4d495c6eSApple OSS Distributions 	}
1035*4d495c6eSApple OSS Distributions 	return 0;
1036*4d495c6eSApple OSS Distributions }
1037*4d495c6eSApple OSS Distributions 
1038*4d495c6eSApple OSS Distributions /**
1039*4d495c6eSApple OSS Distributions **  stolen from bootp/IPConfiguration.bproj/iputil.c
1040*4d495c6eSApple OSS Distributions **
1041*4d495c6eSApple OSS Distributions ** inet6_addrlist_*
1042*4d495c6eSApple OSS Distributions **/
1043*4d495c6eSApple OSS Distributions 
1044*4d495c6eSApple OSS Distributions #define s6_addr16 __u6_addr.__u6_addr16
1045*4d495c6eSApple OSS Distributions 
1046*4d495c6eSApple OSS Distributions static char *
copy_if_info(unsigned int if_index,int af,int * ret_len_p)1047*4d495c6eSApple OSS Distributions copy_if_info(unsigned int if_index, int af, int *ret_len_p)
1048*4d495c6eSApple OSS Distributions {
1049*4d495c6eSApple OSS Distributions 	char *          buf = NULL;
1050*4d495c6eSApple OSS Distributions 	size_t          buf_len = 0;
1051*4d495c6eSApple OSS Distributions 	int             mib[6];
1052*4d495c6eSApple OSS Distributions 
1053*4d495c6eSApple OSS Distributions 	mib[0] = CTL_NET;
1054*4d495c6eSApple OSS Distributions 	mib[1] = PF_ROUTE;
1055*4d495c6eSApple OSS Distributions 	mib[2] = 0;
1056*4d495c6eSApple OSS Distributions 	mib[3] = af;
1057*4d495c6eSApple OSS Distributions 	mib[4] = NET_RT_IFLIST;
1058*4d495c6eSApple OSS Distributions 	mib[5] = (int)if_index;
1059*4d495c6eSApple OSS Distributions 
1060*4d495c6eSApple OSS Distributions 	*ret_len_p = 0;
1061*4d495c6eSApple OSS Distributions 	if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) {
1062*4d495c6eSApple OSS Distributions 		T_LOG("sysctl() size failed: %s", strerror(errno));
1063*4d495c6eSApple OSS Distributions 		goto failed;
1064*4d495c6eSApple OSS Distributions 	}
1065*4d495c6eSApple OSS Distributions 	buf_len *= 2; /* just in case something changes */
1066*4d495c6eSApple OSS Distributions 	buf = malloc(buf_len);
1067*4d495c6eSApple OSS Distributions 	if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) {
1068*4d495c6eSApple OSS Distributions 		free(buf);
1069*4d495c6eSApple OSS Distributions 		buf = NULL;
1070*4d495c6eSApple OSS Distributions 		T_LOG("sysctl() failed: %s", strerror(errno));
1071*4d495c6eSApple OSS Distributions 		goto failed;
1072*4d495c6eSApple OSS Distributions 	}
1073*4d495c6eSApple OSS Distributions 	*ret_len_p = (int)buf_len;
1074*4d495c6eSApple OSS Distributions 
1075*4d495c6eSApple OSS Distributions failed:
1076*4d495c6eSApple OSS Distributions 	return buf;
1077*4d495c6eSApple OSS Distributions }
1078*4d495c6eSApple OSS Distributions 
1079*4d495c6eSApple OSS Distributions bool
inet6_get_linklocal_address(unsigned int if_index,struct in6_addr * ret_addr)1080*4d495c6eSApple OSS Distributions inet6_get_linklocal_address(unsigned int if_index, struct in6_addr *ret_addr)
1081*4d495c6eSApple OSS Distributions {
1082*4d495c6eSApple OSS Distributions 	char *          buf = NULL;
1083*4d495c6eSApple OSS Distributions 	char *          buf_end;
1084*4d495c6eSApple OSS Distributions 	int             buf_len;
1085*4d495c6eSApple OSS Distributions 	bool            found = FALSE;
1086*4d495c6eSApple OSS Distributions 	char *scan;
1087*4d495c6eSApple OSS Distributions 	struct rt_msghdr *rtm;
1088*4d495c6eSApple OSS Distributions 
1089*4d495c6eSApple OSS Distributions 	bzero(ret_addr, sizeof(*ret_addr));
1090*4d495c6eSApple OSS Distributions 	buf = copy_if_info(if_index, AF_INET6, &buf_len);
1091*4d495c6eSApple OSS Distributions 	if (buf == NULL) {
1092*4d495c6eSApple OSS Distributions 		goto done;
1093*4d495c6eSApple OSS Distributions 	}
1094*4d495c6eSApple OSS Distributions 	buf_end = buf + buf_len;
1095*4d495c6eSApple OSS Distributions 	for (scan = buf; scan < buf_end; scan += rtm->rtm_msglen) {
1096*4d495c6eSApple OSS Distributions 		struct ifa_msghdr * ifam;
1097*4d495c6eSApple OSS Distributions 		struct rt_addrinfo  info;
1098*4d495c6eSApple OSS Distributions 
1099*4d495c6eSApple OSS Distributions 		/* ALIGN: buf aligned (from calling copy_if_info), scan aligned,
1100*4d495c6eSApple OSS Distributions 		 * cast ok. */
1101*4d495c6eSApple OSS Distributions 		rtm = (struct rt_msghdr *)(void *)scan;
1102*4d495c6eSApple OSS Distributions 		T_LOG("rtm_version %d rtm_type %d", rtm->rtm_version, rtm->rtm_type);
1103*4d495c6eSApple OSS Distributions 		if (rtm->rtm_version != RTM_VERSION) {
1104*4d495c6eSApple OSS Distributions 			continue;
1105*4d495c6eSApple OSS Distributions 		}
1106*4d495c6eSApple OSS Distributions 		if (rtm->rtm_type == RTM_NEWADDR) {
1107*4d495c6eSApple OSS Distributions 			errno_t         error;
1108*4d495c6eSApple OSS Distributions 			struct sockaddr_in6 *sin6_p;
1109*4d495c6eSApple OSS Distributions 
1110*4d495c6eSApple OSS Distributions 			ifam = (struct ifa_msghdr *)rtm;
1111*4d495c6eSApple OSS Distributions 			info.rti_addrs = ifam->ifam_addrs;
1112*4d495c6eSApple OSS Distributions 			error = rt_xaddrs((char *)(ifam + 1),
1113*4d495c6eSApple OSS Distributions 			    ((char *)ifam) + ifam->ifam_msglen,
1114*4d495c6eSApple OSS Distributions 			    &info);
1115*4d495c6eSApple OSS Distributions 			if (error) {
1116*4d495c6eSApple OSS Distributions 				T_LOG("couldn't extract rt_addrinfo %s (%d)\n",
1117*4d495c6eSApple OSS Distributions 				    strerror(error), error);
1118*4d495c6eSApple OSS Distributions 				goto done;
1119*4d495c6eSApple OSS Distributions 			}
1120*4d495c6eSApple OSS Distributions 			/* ALIGN: info.rti_info aligned (sockaddr), cast ok. */
1121*4d495c6eSApple OSS Distributions 			sin6_p = (struct sockaddr_in6 *)(void *)info.rti_info[RTAX_IFA];
1122*4d495c6eSApple OSS Distributions 			if (sin6_p == NULL
1123*4d495c6eSApple OSS Distributions 			    || sin6_p->sin6_len < sizeof(struct sockaddr_in6)) {
1124*4d495c6eSApple OSS Distributions 				continue;
1125*4d495c6eSApple OSS Distributions 			}
1126*4d495c6eSApple OSS Distributions 			if (IN6_IS_ADDR_LINKLOCAL(&sin6_p->sin6_addr)) {
1127*4d495c6eSApple OSS Distributions 				*ret_addr = sin6_p->sin6_addr;
1128*4d495c6eSApple OSS Distributions 				ret_addr->s6_addr16[1] = 0; /* mask scope id */
1129*4d495c6eSApple OSS Distributions 				found = TRUE;
1130*4d495c6eSApple OSS Distributions 				break;
1131*4d495c6eSApple OSS Distributions 			}
1132*4d495c6eSApple OSS Distributions 		}
1133*4d495c6eSApple OSS Distributions 	}
1134*4d495c6eSApple OSS Distributions 
1135*4d495c6eSApple OSS Distributions done:
1136*4d495c6eSApple OSS Distributions 	if (buf != NULL) {
1137*4d495c6eSApple OSS Distributions 		free(buf);
1138*4d495c6eSApple OSS Distributions 	}
1139*4d495c6eSApple OSS Distributions 	return found;
1140*4d495c6eSApple OSS Distributions }
1141*4d495c6eSApple OSS Distributions 
1142*4d495c6eSApple OSS Distributions void
force_zone_gc(void)1143*4d495c6eSApple OSS Distributions force_zone_gc(void)
1144*4d495c6eSApple OSS Distributions {
1145*4d495c6eSApple OSS Distributions 	kern_return_t kr = mach_zone_force_gc(mach_host_self());
1146*4d495c6eSApple OSS Distributions 
1147*4d495c6eSApple OSS Distributions 	if (kr != KERN_SUCCESS) {
1148*4d495c6eSApple OSS Distributions 		T_LOG("mach_zone_force_gc(): failed with error %s\n", mach_error_string(kr));
1149*4d495c6eSApple OSS Distributions 	} else {
1150*4d495c6eSApple OSS Distributions 		T_LOG("mach_zone_force_gc(): success\n");
1151*4d495c6eSApple OSS Distributions 	}
1152*4d495c6eSApple OSS Distributions }
1153