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