1 /*
2 * Copyright (c) 2019-2023 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include "net_test_lib.h"
30 #include "inet_transfer.h"
31 #include "bpflib.h"
32 #include "in_cksum.h"
33
34 bool S_debug;
35
36 int
inet_dgram_socket(void)37 inet_dgram_socket(void)
38 {
39 int s;
40
41 s = socket(AF_INET, SOCK_DGRAM, 0);
42 T_QUIET;
43 T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET, SOCK_DGRAM, 0)");
44 return s;
45 }
46
47 int
inet6_dgram_socket(void)48 inet6_dgram_socket(void)
49 {
50 int s;
51
52 s = socket(AF_INET6, SOCK_DGRAM, 0);
53 T_QUIET;
54 T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET6, SOCK_DGRAM, 0)");
55 return s;
56 }
57
58 int
routing_socket(void)59 routing_socket(void)
60 {
61 int s;
62
63 s = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE);
64 T_QUIET;
65 T_ASSERT_POSIX_SUCCESS(s, "socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)");
66 return s;
67 }
68
69 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)70 ethernet_udp4_frame_populate(void * buf, size_t buf_len,
71 const ether_addr_t * src,
72 struct in_addr src_ip,
73 uint16_t src_port,
74 const ether_addr_t * dst,
75 struct in_addr dst_ip,
76 uint16_t dst_port,
77 const void * data, u_int data_len)
78 {
79 ether_header_t * eh_p;
80 u_int frame_length;
81 static int ip_id;
82 ip_udp_header_t * ip_udp;
83 char * payload;
84 udp_pseudo_hdr_t * udp_pseudo;
85
86 frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)) + data_len;
87 if (buf_len < frame_length) {
88 return 0;
89 }
90
91 /* determine frame offsets */
92 eh_p = (ether_header_t *)buf;
93 ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
94 udp_pseudo = (udp_pseudo_hdr_t *)(void *)
95 (((char *)&ip_udp->udp) - sizeof(*udp_pseudo));
96 payload = (char *)(eh_p + 1) + sizeof(*ip_udp);
97
98 /* ethernet_header */
99 bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
100 bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
101 eh_p->ether_type = htons(ETHERTYPE_IP);
102
103 /* copy the data */
104 bcopy(data, payload, data_len);
105
106 /* fill in UDP pseudo header (gets overwritten by IP header below) */
107 bcopy(&src_ip, &udp_pseudo->src_ip, sizeof(src_ip));
108 bcopy(&dst_ip, &udp_pseudo->dst_ip, sizeof(dst_ip));
109 udp_pseudo->zero = 0;
110 udp_pseudo->proto = IPPROTO_UDP;
111 udp_pseudo->length = htons(sizeof(ip_udp->udp) + data_len);
112
113 /* fill in UDP header */
114 ip_udp->udp.uh_sport = htons(src_port);
115 ip_udp->udp.uh_dport = htons(dst_port);
116 ip_udp->udp.uh_ulen = htons(sizeof(ip_udp->udp) + data_len);
117 ip_udp->udp.uh_sum = 0;
118 ip_udp->udp.uh_sum = in_cksum(udp_pseudo, (int)(sizeof(*udp_pseudo)
119 + sizeof(ip_udp->udp) + data_len));
120
121 /* fill in IP header */
122 bzero(ip_udp, sizeof(ip_udp->ip));
123 ip_udp->ip.ip_v = IPVERSION;
124 ip_udp->ip.ip_hl = sizeof(struct ip) >> 2;
125 ip_udp->ip.ip_ttl = MAXTTL;
126 ip_udp->ip.ip_p = IPPROTO_UDP;
127 bcopy(&src_ip, &ip_udp->ip.ip_src, sizeof(src_ip));
128 bcopy(&dst_ip, &ip_udp->ip.ip_dst, sizeof(dst_ip));
129 ip_udp->ip.ip_len = htons(sizeof(*ip_udp) + data_len);
130 ip_udp->ip.ip_id = htons(ip_id++);
131
132 /* compute the IP checksum */
133 ip_udp->ip.ip_sum = 0; /* needs to be zero for checksum */
134 ip_udp->ip.ip_sum = in_cksum(&ip_udp->ip, sizeof(ip_udp->ip));
135
136 return frame_length;
137 }
138
139 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)140 ethernet_udp6_frame_populate(void * buf, size_t buf_len,
141 const ether_addr_t * src,
142 struct in6_addr *src_ip,
143 uint16_t src_port,
144 const ether_addr_t * dst,
145 struct in6_addr * dst_ip,
146 uint16_t dst_port,
147 const void * data, u_int data_len)
148 {
149 ether_header_t * eh_p;
150 u_int frame_length;
151 ip6_udp_header_t * ip6_udp;
152 char * payload;
153 udp6_pseudo_hdr_t * udp6_pseudo;
154
155 frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)) + data_len;
156 if (buf_len < frame_length) {
157 return 0;
158 }
159
160 /* determine frame offsets */
161 eh_p = (ether_header_t *)buf;
162 ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
163 udp6_pseudo = (udp6_pseudo_hdr_t *)(void *)
164 (((char *)&ip6_udp->udp) - sizeof(*udp6_pseudo));
165 payload = (char *)(eh_p + 1) + sizeof(*ip6_udp);
166
167 /* ethernet_header */
168 bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
169 bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
170 eh_p->ether_type = htons(ETHERTYPE_IPV6);
171
172 /* copy the data */
173 bcopy(data, payload, data_len);
174
175 /* fill in UDP pseudo header (gets overwritten by IP header below) */
176 bcopy(src_ip, &udp6_pseudo->src_ip, sizeof(*src_ip));
177 bcopy(dst_ip, &udp6_pseudo->dst_ip, sizeof(*dst_ip));
178 udp6_pseudo->zero = 0;
179 udp6_pseudo->proto = IPPROTO_UDP;
180 udp6_pseudo->length = htons(sizeof(ip6_udp->udp) + data_len);
181
182 /* fill in UDP header */
183 ip6_udp->udp.uh_sport = htons(src_port);
184 ip6_udp->udp.uh_dport = htons(dst_port);
185 ip6_udp->udp.uh_ulen = htons(sizeof(ip6_udp->udp) + data_len);
186 ip6_udp->udp.uh_sum = 0;
187 ip6_udp->udp.uh_sum = in_cksum(udp6_pseudo, (int)(sizeof(*udp6_pseudo)
188 + sizeof(ip6_udp->udp) + data_len));
189
190 /* fill in IP header */
191 bzero(&ip6_udp->ip6, sizeof(ip6_udp->ip6));
192 ip6_udp->ip6.ip6_vfc = IPV6_VERSION;
193 ip6_udp->ip6.ip6_nxt = IPPROTO_UDP;
194 bcopy(src_ip, &ip6_udp->ip6.ip6_src, sizeof(*src_ip));
195 bcopy(dst_ip, &ip6_udp->ip6.ip6_dst, sizeof(*dst_ip));
196 ip6_udp->ip6.ip6_plen = htons(sizeof(struct udphdr) + data_len);
197 /* ip6_udp->ip6.ip6_flow = ? */
198 return frame_length;
199 }
200
201 /**
202 ** interface management
203 **/
204
205 void
ifnet_get_lladdr(int s,const char * ifname,ether_addr_t * eaddr)206 ifnet_get_lladdr(int s, const char * ifname, ether_addr_t * eaddr)
207 {
208 int err;
209 struct ifreq ifr;
210
211 bzero(&ifr, sizeof(ifr));
212 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
213 ifr.ifr_addr.sa_family = AF_LINK;
214 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
215 err = ioctl(s, SIOCGIFLLADDR, &ifr);
216 T_QUIET;
217 T_ASSERT_POSIX_SUCCESS(err, "SIOCGIFLLADDR %s", ifname);
218 bcopy(ifr.ifr_addr.sa_data, eaddr->octet, ETHER_ADDR_LEN);
219 return;
220 }
221
222
223 int
ifnet_attach_ip(int s,char * name)224 ifnet_attach_ip(int s, char * name)
225 {
226 int err;
227 struct ifreq ifr;
228
229 bzero(&ifr, sizeof(ifr));
230 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
231 err = ioctl(s, SIOCPROTOATTACH, &ifr);
232 T_QUIET;
233 T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTOATTACH %s", ifr.ifr_name);
234 return err;
235 }
236
237 int
ifnet_destroy(int s,const char * ifname,bool fail_on_error)238 ifnet_destroy(int s, const char * ifname, bool fail_on_error)
239 {
240 int err;
241 struct ifreq ifr;
242
243 bzero(&ifr, sizeof(ifr));
244 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
245 err = ioctl(s, SIOCIFDESTROY, &ifr);
246 if (fail_on_error) {
247 T_QUIET;
248 T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
249 }
250 if (err < 0) {
251 T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
252 }
253 return err;
254 }
255
256 int
ifnet_set_flags(int s,const char * ifname,uint16_t flags_set,uint16_t flags_clear)257 ifnet_set_flags(int s, const char * ifname,
258 uint16_t flags_set, uint16_t flags_clear)
259 {
260 uint16_t flags_after;
261 uint16_t flags_before;
262 struct ifreq ifr;
263 int ret;
264
265 bzero(&ifr, sizeof(ifr));
266 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
267 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
268 if (ret != 0) {
269 T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
270 return ret;
271 }
272 flags_before = (uint16_t)ifr.ifr_flags;
273 ifr.ifr_flags |= flags_set;
274 ifr.ifr_flags &= ~(flags_clear);
275 flags_after = (uint16_t)ifr.ifr_flags;
276 if (flags_before == flags_after) {
277 /* nothing to do */
278 ret = 0;
279 } else {
280 /* issue the ioctl */
281 T_QUIET;
282 T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
283 "SIOCSIFFLAGS %s 0x%x",
284 ifr.ifr_name, (uint16_t)ifr.ifr_flags);
285 if (S_debug) {
286 T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
287 ifr.ifr_name, flags_set, flags_clear,
288 flags_before, flags_after);
289 }
290 }
291 return ret;
292 }
293
294 #define FETH_NAME "feth"
295
296 /* On some platforms with DEBUG kernel, we need to wait a while */
297 #define SIFCREATE_RETRY 600
298
299 static int
ifnet_create_common(int s,const char * ifname,char * ifname_out,size_t ifname_out_len)300 ifnet_create_common(int s, const char * ifname, char *ifname_out, size_t ifname_out_len)
301 {
302 int error = 0;
303 struct ifreq ifr;
304
305 bzero(&ifr, sizeof(ifr));
306 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
307
308 for (int i = 0; i < SIFCREATE_RETRY; i++) {
309 if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
310 error = errno;
311 T_LOG("SIOCSIFCREATE %s: %s", ifname,
312 strerror(error));
313 if (error == EBUSY) {
314 /* interface is tearing down, try again */
315 usleep(10000);
316 } else if (error == EEXIST) {
317 /* interface exists, try destroying it */
318 (void)ifnet_destroy(s, ifname, false);
319 } else {
320 /* unexpected failure */
321 break;
322 }
323 } else {
324 if (ifname_out != NULL) {
325 strlcpy(ifname_out, ifr.ifr_name, ifname_out_len);
326 }
327 error = 0;
328 break;
329 }
330 }
331 if (error == 0) {
332 error = ifnet_set_flags(s, ifname, IFF_UP, 0);
333 }
334 return error;
335 }
336
337 int
ifnet_create(int s,const char * ifname)338 ifnet_create(int s, const char * ifname)
339 {
340 return ifnet_create_common(s, ifname, NULL, 0);
341 }
342
343 int
ifnet_create_2(int s,char * ifname,size_t len)344 ifnet_create_2(int s, char * ifname, size_t len)
345 {
346 return ifnet_create_common(s, ifname, ifname, len);
347 }
348
349 int
siocdrvspec(int s,const char * ifname,u_long op,void * arg,size_t argsize,bool set)350 siocdrvspec(int s, const char * ifname,
351 u_long op, void *arg, size_t argsize, bool set)
352 {
353 struct ifdrv ifd;
354
355 memset(&ifd, 0, sizeof(ifd));
356 strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
357 ifd.ifd_cmd = op;
358 ifd.ifd_len = argsize;
359 ifd.ifd_data = arg;
360 return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
361 }
362
363 int
fake_set_peer(int s,const char * feth,const char * feth_peer)364 fake_set_peer(int s, const char * feth, const char * feth_peer)
365 {
366 struct if_fake_request iffr;
367 int ret;
368
369 bzero((char *)&iffr, sizeof(iffr));
370 if (feth_peer != NULL) {
371 strlcpy(iffr.iffr_peer_name, feth_peer,
372 sizeof(iffr.iffr_peer_name));
373 }
374 ret = siocdrvspec(s, feth, IF_FAKE_S_CMD_SET_PEER,
375 &iffr, sizeof(iffr), true);
376 T_QUIET;
377 T_ASSERT_POSIX_SUCCESS(ret,
378 "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
379 feth, (feth_peer != NULL) ? feth_peer : "<none>");
380 return ret;
381 }
382
383 u_int
make_dhcp_payload(dhcp_min_payload_t payload,ether_addr_t * eaddr)384 make_dhcp_payload(dhcp_min_payload_t payload, ether_addr_t *eaddr)
385 {
386 struct bootp * dhcp;
387 u_int payload_length;
388
389 /* create a minimal BOOTP packet */
390 payload_length = sizeof(*payload);
391 dhcp = (struct bootp *)payload;
392 bzero(dhcp, payload_length);
393 dhcp->bp_op = BOOTREQUEST;
394 dhcp->bp_htype = ARPHRD_ETHER;
395 dhcp->bp_hlen = sizeof(*eaddr);
396 bcopy(eaddr->octet, dhcp->bp_chaddr, sizeof(eaddr->octet));
397 return payload_length;
398 }
399