1*043036a2SApple OSS Distributions /*
2*043036a2SApple OSS Distributions * Copyright (c) 2025 Apple Inc. All rights reserved.
3*043036a2SApple OSS Distributions *
4*043036a2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*043036a2SApple OSS Distributions *
6*043036a2SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*043036a2SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*043036a2SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*043036a2SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*043036a2SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*043036a2SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*043036a2SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*043036a2SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*043036a2SApple OSS Distributions *
15*043036a2SApple OSS Distributions * Please obtain a copy of the License at
16*043036a2SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*043036a2SApple OSS Distributions *
18*043036a2SApple OSS Distributions * The Original Code and all software distributed under the License are
19*043036a2SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*043036a2SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*043036a2SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*043036a2SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*043036a2SApple OSS Distributions * Please see the License for the specific language governing rights and
24*043036a2SApple OSS Distributions * limitations under the License.
25*043036a2SApple OSS Distributions *
26*043036a2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*043036a2SApple OSS Distributions */
28*043036a2SApple OSS Distributions
29*043036a2SApple OSS Distributions #define __APPLE_USE_RFC_3542 1
30*043036a2SApple OSS Distributions
31*043036a2SApple OSS Distributions #include <darwintest.h>
32*043036a2SApple OSS Distributions
33*043036a2SApple OSS Distributions #include <sys/socket.h>
34*043036a2SApple OSS Distributions #include <netinet/in.h>
35*043036a2SApple OSS Distributions #include <arpa/inet.h>
36*043036a2SApple OSS Distributions #include <unistd.h>
37*043036a2SApple OSS Distributions
38*043036a2SApple OSS Distributions #include "net_test_lib.h"
39*043036a2SApple OSS Distributions
40*043036a2SApple OSS Distributions #define MAX_IPv4_STR_LEN 16
41*043036a2SApple OSS Distributions #define MAX_IPv6_STR_LEN 64
42*043036a2SApple OSS Distributions
43*043036a2SApple OSS Distributions T_GLOBAL_META(
44*043036a2SApple OSS Distributions T_META_NAMESPACE("xnu.net"),
45*043036a2SApple OSS Distributions T_META_ASROOT(true),
46*043036a2SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
47*043036a2SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("networking"),
48*043036a2SApple OSS Distributions T_META_CHECK_LEAKS(false));
49*043036a2SApple OSS Distributions
50*043036a2SApple OSS Distributions static char *ifname1;
51*043036a2SApple OSS Distributions static char *ifname2;
52*043036a2SApple OSS Distributions
53*043036a2SApple OSS Distributions #define IPV4_MULTICAST_ADDR_STR "239.1.2.3"
54*043036a2SApple OSS Distributions #define IPV6_MULTICAST_ADDR_STR "FF12:0:0:0:0:0:0:FC"
55*043036a2SApple OSS Distributions
56*043036a2SApple OSS Distributions #define TEN_NET 0x0a000000
57*043036a2SApple OSS Distributions #define TEN_1_NET (TEN_NET | 0x010000)
58*043036a2SApple OSS Distributions #define TEN_1_BROADCAST (TEN_1_NET | 0xff)
59*043036a2SApple OSS Distributions
60*043036a2SApple OSS Distributions static network_interface_pair_list_t S_feth_pairs;
61*043036a2SApple OSS Distributions
62*043036a2SApple OSS Distributions
63*043036a2SApple OSS Distributions static char *data = "hello\n";
64*043036a2SApple OSS Distributions
65*043036a2SApple OSS Distributions static bool success = false;
66*043036a2SApple OSS Distributions
67*043036a2SApple OSS Distributions static void
get_ipv4_address(u_int unit,u_int addr_index,struct in_addr * ip)68*043036a2SApple OSS Distributions get_ipv4_address(u_int unit, u_int addr_index, struct in_addr *ip)
69*043036a2SApple OSS Distributions {
70*043036a2SApple OSS Distributions /* up to 255 units, 255 addresses */
71*043036a2SApple OSS Distributions ip->s_addr = htonl(TEN_1_NET | (unit << 8) | addr_index);
72*043036a2SApple OSS Distributions return;
73*043036a2SApple OSS Distributions }
74*043036a2SApple OSS Distributions
75*043036a2SApple OSS Distributions static void
network_interface_assign_address(network_interface_t netif,unsigned int unit,unsigned int address_index)76*043036a2SApple OSS Distributions network_interface_assign_address(network_interface_t netif,
77*043036a2SApple OSS Distributions unsigned int unit, unsigned int address_index)
78*043036a2SApple OSS Distributions {
79*043036a2SApple OSS Distributions get_ipv4_address(unit, address_index, &netif->ip);
80*043036a2SApple OSS Distributions ifnet_add_ip_address(netif->if_name, netif->ip,
81*043036a2SApple OSS Distributions inet_class_c_subnet_mask);
82*043036a2SApple OSS Distributions route_add_inet_scoped_subnet(netif->if_name, netif->if_index,
83*043036a2SApple OSS Distributions netif->ip, inet_class_c_subnet_mask);
84*043036a2SApple OSS Distributions ifnet_start_ipv6(netif->if_name);
85*043036a2SApple OSS Distributions T_ASSERT_EQ(inet6_get_linklocal_address(netif->if_index, &netif->ip6), 1, NULL);
86*043036a2SApple OSS Distributions }
87*043036a2SApple OSS Distributions
88*043036a2SApple OSS Distributions static void
initialize_feth_pairs(u_int n,bool need_address)89*043036a2SApple OSS Distributions initialize_feth_pairs(u_int n, bool need_address)
90*043036a2SApple OSS Distributions {
91*043036a2SApple OSS Distributions network_interface_pair_t scan;
92*043036a2SApple OSS Distributions
93*043036a2SApple OSS Distributions S_feth_pairs = network_interface_pair_list_alloc(n);
94*043036a2SApple OSS Distributions scan = S_feth_pairs->list;
95*043036a2SApple OSS Distributions for (unsigned int i = 0; i < n; i++, scan++) {
96*043036a2SApple OSS Distributions network_interface_create(&scan->one, FETH_NAME);
97*043036a2SApple OSS Distributions network_interface_create(&scan->two, FETH_NAME);
98*043036a2SApple OSS Distributions if (need_address) {
99*043036a2SApple OSS Distributions network_interface_assign_address(&scan->one, i, 1);
100*043036a2SApple OSS Distributions network_interface_assign_address(&scan->two, i, 2);
101*043036a2SApple OSS Distributions }
102*043036a2SApple OSS Distributions fake_set_peer(scan->one.if_name, scan->two.if_name);
103*043036a2SApple OSS Distributions }
104*043036a2SApple OSS Distributions
105*043036a2SApple OSS Distributions ifname1 = S_feth_pairs->list->one.if_name;
106*043036a2SApple OSS Distributions ifname2 = S_feth_pairs->list->two.if_name;
107*043036a2SApple OSS Distributions }
108*043036a2SApple OSS Distributions
109*043036a2SApple OSS Distributions static void
cleanup(void)110*043036a2SApple OSS Distributions cleanup(void)
111*043036a2SApple OSS Distributions {
112*043036a2SApple OSS Distributions network_interface_pair_list_destroy(S_feth_pairs);
113*043036a2SApple OSS Distributions /* allow for the detach to be final before the next test */
114*043036a2SApple OSS Distributions usleep(100000);
115*043036a2SApple OSS Distributions }
116*043036a2SApple OSS Distributions
117*043036a2SApple OSS Distributions static void
init(void)118*043036a2SApple OSS Distributions init(void)
119*043036a2SApple OSS Distributions {
120*043036a2SApple OSS Distributions T_ATEND(cleanup);
121*043036a2SApple OSS Distributions
122*043036a2SApple OSS Distributions success = false;
123*043036a2SApple OSS Distributions initialize_feth_pairs(1, true);
124*043036a2SApple OSS Distributions }
125*043036a2SApple OSS Distributions
126*043036a2SApple OSS Distributions static int
setup_receiver(char * bind_to_ifname,bool bind_to_port,in_addr_t bind_to_addr,in_port_t * bound_port)127*043036a2SApple OSS Distributions setup_receiver(char *bind_to_ifname, bool bind_to_port, in_addr_t bind_to_addr, in_port_t *bound_port)
128*043036a2SApple OSS Distributions {
129*043036a2SApple OSS Distributions int receiver_fd;
130*043036a2SApple OSS Distributions socklen_t solen;
131*043036a2SApple OSS Distributions struct sockaddr_in sin = {};
132*043036a2SApple OSS Distributions char ifname[IFNAMSIZ];
133*043036a2SApple OSS Distributions char laddr_str[MAX_IPv4_STR_LEN];
134*043036a2SApple OSS Distributions struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
135*043036a2SApple OSS Distributions int optval;
136*043036a2SApple OSS Distributions
137*043036a2SApple OSS Distributions /*
138*043036a2SApple OSS Distributions * Setup receiver bound to ifname1
139*043036a2SApple OSS Distributions */
140*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(receiver_fd = socket(AF_INET, SOCK_DGRAM, 0), NULL);
141*043036a2SApple OSS Distributions
142*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(receiver_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)), NULL);
143*043036a2SApple OSS Distributions
144*043036a2SApple OSS Distributions optval = 1;
145*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(receiver_fd, SOL_SOCKET, SO_DEBUG, &optval, sizeof(int)), NULL);
146*043036a2SApple OSS Distributions
147*043036a2SApple OSS Distributions optval = 1;
148*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(receiver_fd, IPPROTO_IP, IP_RECVPKTINFO, &optval, sizeof(int)), NULL);
149*043036a2SApple OSS Distributions
150*043036a2SApple OSS Distributions optval = 1;
151*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(receiver_fd, IPPROTO_UDP, UDP_NOCKSUM, &optval, sizeof(int)), NULL);
152*043036a2SApple OSS Distributions
153*043036a2SApple OSS Distributions if (bind_to_ifname != NULL) {
154*043036a2SApple OSS Distributions solen = strlen(bind_to_ifname);
155*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(receiver_fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_ifname, solen), NULL);
156*043036a2SApple OSS Distributions }
157*043036a2SApple OSS Distributions
158*043036a2SApple OSS Distributions if (bind_to_port || bind_to_addr != INADDR_ANY) {
159*043036a2SApple OSS Distributions sin.sin_family = AF_INET;
160*043036a2SApple OSS Distributions sin.sin_len = sizeof(struct sockaddr_in);
161*043036a2SApple OSS Distributions sin.sin_addr.s_addr = bind_to_addr;
162*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(bind(receiver_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)), NULL);
163*043036a2SApple OSS Distributions }
164*043036a2SApple OSS Distributions solen = sizeof(struct sockaddr_in);
165*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockname(receiver_fd, (struct sockaddr *)&sin, &solen), NULL);
166*043036a2SApple OSS Distributions inet_ntop(AF_INET, &sin.sin_addr, laddr_str, sizeof(laddr_str));
167*043036a2SApple OSS Distributions
168*043036a2SApple OSS Distributions solen = sizeof(ifname);
169*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockopt(receiver_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, &solen), NULL);
170*043036a2SApple OSS Distributions
171*043036a2SApple OSS Distributions T_LOG("receiver bound to %s:%u over '%s'", laddr_str, ntohs(sin.sin_port), ifname);
172*043036a2SApple OSS Distributions
173*043036a2SApple OSS Distributions *bound_port = sin.sin_port;
174*043036a2SApple OSS Distributions return receiver_fd;
175*043036a2SApple OSS Distributions }
176*043036a2SApple OSS Distributions
177*043036a2SApple OSS Distributions int
setup_sender(char * bind_to_ifname,in_addr_t connect_to_addr,in_port_t connect_to_port)178*043036a2SApple OSS Distributions setup_sender(char *bind_to_ifname, in_addr_t connect_to_addr, in_port_t connect_to_port)
179*043036a2SApple OSS Distributions {
180*043036a2SApple OSS Distributions int sender_fd;
181*043036a2SApple OSS Distributions struct sockaddr_in connect_to_sin = {};
182*043036a2SApple OSS Distributions struct sockaddr_in sin = {};
183*043036a2SApple OSS Distributions socklen_t solen;
184*043036a2SApple OSS Distributions char laddr_str[MAX_IPv4_STR_LEN];
185*043036a2SApple OSS Distributions char faddr_str[MAX_IPv4_STR_LEN];
186*043036a2SApple OSS Distributions char ifname[IFNAMSIZ];
187*043036a2SApple OSS Distributions struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
188*043036a2SApple OSS Distributions int optval;
189*043036a2SApple OSS Distributions
190*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sender_fd = socket(AF_INET, SOCK_DGRAM, 0), NULL);
191*043036a2SApple OSS Distributions
192*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)), NULL);
193*043036a2SApple OSS Distributions
194*043036a2SApple OSS Distributions optval = 1;
195*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_DEBUG, &optval, sizeof(int)), NULL);
196*043036a2SApple OSS Distributions
197*043036a2SApple OSS Distributions optval = 1;
198*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, IPPROTO_IP, IP_RECVPKTINFO, &optval, sizeof(int)), NULL);
199*043036a2SApple OSS Distributions
200*043036a2SApple OSS Distributions optval = 1;
201*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, IPPROTO_UDP, UDP_NOCKSUM, &optval, sizeof(int)), NULL);
202*043036a2SApple OSS Distributions
203*043036a2SApple OSS Distributions if (bind_to_ifname != NULL) {
204*043036a2SApple OSS Distributions solen = strlen(bind_to_ifname);
205*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(setsockopt(sender_fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_ifname, solen), NULL);
206*043036a2SApple OSS Distributions }
207*043036a2SApple OSS Distributions
208*043036a2SApple OSS Distributions connect_to_sin.sin_family = AF_INET;
209*043036a2SApple OSS Distributions connect_to_sin.sin_len = sizeof(struct sockaddr_in);
210*043036a2SApple OSS Distributions connect_to_sin.sin_port = connect_to_port;
211*043036a2SApple OSS Distributions connect_to_sin.sin_addr.s_addr = connect_to_addr;
212*043036a2SApple OSS Distributions
213*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(connect(sender_fd, (struct sockaddr *)&connect_to_sin, sizeof(struct sockaddr_in)), NULL);
214*043036a2SApple OSS Distributions
215*043036a2SApple OSS Distributions solen = sizeof(struct sockaddr_in);
216*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockname(sender_fd, (struct sockaddr *)&sin, &solen), NULL);
217*043036a2SApple OSS Distributions inet_ntop(AF_INET, &sin.sin_addr, laddr_str, sizeof(laddr_str));
218*043036a2SApple OSS Distributions inet_ntop(AF_INET, &connect_to_sin.sin_addr, faddr_str, sizeof(faddr_str));
219*043036a2SApple OSS Distributions
220*043036a2SApple OSS Distributions solen = sizeof(ifname);
221*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockopt(sender_fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, &solen), NULL);
222*043036a2SApple OSS Distributions
223*043036a2SApple OSS Distributions T_LOG("sender_fd connected from %s:%u to %s:%u over '%s'",
224*043036a2SApple OSS Distributions laddr_str, ntohs(sin.sin_port), faddr_str, ntohs(connect_to_sin.sin_port),
225*043036a2SApple OSS Distributions ifname);
226*043036a2SApple OSS Distributions
227*043036a2SApple OSS Distributions return sender_fd;
228*043036a2SApple OSS Distributions }
229*043036a2SApple OSS Distributions
230*043036a2SApple OSS Distributions
231*043036a2SApple OSS Distributions static void
echo(int receiver_fd,bool by_ip_addr)232*043036a2SApple OSS Distributions echo(int receiver_fd, bool by_ip_addr)
233*043036a2SApple OSS Distributions {
234*043036a2SApple OSS Distributions struct msghdr recvmsghdr = {};
235*043036a2SApple OSS Distributions char control_space[CMSG_SPACE(128)] = {};
236*043036a2SApple OSS Distributions char packet_space[1500] = {};
237*043036a2SApple OSS Distributions struct cmsghdr *cmsg;
238*043036a2SApple OSS Distributions ssize_t retval;
239*043036a2SApple OSS Distributions struct iovec recv_iov = {};
240*043036a2SApple OSS Distributions struct sockaddr_in peer_addr;
241*043036a2SApple OSS Distributions struct in_pktinfo recv_in_pktinfo = {};
242*043036a2SApple OSS Distributions struct in_pktinfo send_in_pktinfo = {};
243*043036a2SApple OSS Distributions char ifname[IFNAMSIZ] = {};
244*043036a2SApple OSS Distributions struct msghdr reply_msg = {};
245*043036a2SApple OSS Distributions struct iovec reply_iov = {};
246*043036a2SApple OSS Distributions char reply_control_space[CMSG_SPACE(128)] = {};
247*043036a2SApple OSS Distributions char spec_dst_str[MAX_IPv4_STR_LEN];
248*043036a2SApple OSS Distributions char addr_str[MAX_IPv4_STR_LEN];
249*043036a2SApple OSS Distributions char peer_addr_str[MAX_IPv4_STR_LEN];
250*043036a2SApple OSS Distributions
251*043036a2SApple OSS Distributions T_LOG("%s(by_ip_addr: %s)", __func__, by_ip_addr ? "true" : "false");
252*043036a2SApple OSS Distributions
253*043036a2SApple OSS Distributions recv_iov.iov_len = sizeof(packet_space);
254*043036a2SApple OSS Distributions recv_iov.iov_base = &packet_space;
255*043036a2SApple OSS Distributions
256*043036a2SApple OSS Distributions recvmsghdr.msg_name = &peer_addr;
257*043036a2SApple OSS Distributions recvmsghdr.msg_namelen = sizeof(struct sockaddr_in);
258*043036a2SApple OSS Distributions recvmsghdr.msg_iov = &recv_iov;
259*043036a2SApple OSS Distributions recvmsghdr.msg_iovlen = 1;
260*043036a2SApple OSS Distributions recvmsghdr.msg_control = &control_space;
261*043036a2SApple OSS Distributions recvmsghdr.msg_controllen = sizeof(control_space);
262*043036a2SApple OSS Distributions recvmsghdr.msg_flags = 0;
263*043036a2SApple OSS Distributions
264*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(retval = recvmsg(receiver_fd, &recvmsghdr, 0), NULL);
265*043036a2SApple OSS Distributions
266*043036a2SApple OSS Distributions for (cmsg = CMSG_FIRSTHDR(&recvmsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&recvmsghdr, cmsg)) {
267*043036a2SApple OSS Distributions if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVPKTINFO) {
268*043036a2SApple OSS Distributions T_ASSERT_EQ(CMSG_LEN(sizeof(struct in_pktinfo)), (size_t)cmsg->cmsg_len,
269*043036a2SApple OSS Distributions "CMSG_LEN(struct in_pktinfo), (size_t)cmsg->cmsg_len");
270*043036a2SApple OSS Distributions memcpy(&recv_in_pktinfo, CMSG_DATA(cmsg), sizeof(struct in_pktinfo));
271*043036a2SApple OSS Distributions }
272*043036a2SApple OSS Distributions }
273*043036a2SApple OSS Distributions
274*043036a2SApple OSS Distributions ifname[0] = 0;
275*043036a2SApple OSS Distributions if_indextoname(recv_in_pktinfo.ipi_ifindex, ifname);
276*043036a2SApple OSS Distributions inet_ntop(AF_INET, &recv_in_pktinfo.ipi_spec_dst, spec_dst_str, sizeof(spec_dst_str));
277*043036a2SApple OSS Distributions inet_ntop(AF_INET, &recv_in_pktinfo.ipi_addr, addr_str, sizeof(addr_str));
278*043036a2SApple OSS Distributions inet_ntop(AF_INET, &peer_addr.sin_addr, peer_addr_str, sizeof(peer_addr_str));
279*043036a2SApple OSS Distributions
280*043036a2SApple OSS Distributions T_LOG("received %ld bytes from %s:%u with IP_RECVPKTINFO ipi_ifindex: %u (%s) ipi_spec_dst: %s ipi_addr: %s",
281*043036a2SApple OSS Distributions retval, peer_addr_str, ntohs(peer_addr.sin_port),
282*043036a2SApple OSS Distributions recv_in_pktinfo.ipi_ifindex, ifname, spec_dst_str, addr_str);
283*043036a2SApple OSS Distributions
284*043036a2SApple OSS Distributions reply_iov.iov_base = packet_space;
285*043036a2SApple OSS Distributions reply_iov.iov_len = retval;
286*043036a2SApple OSS Distributions
287*043036a2SApple OSS Distributions reply_msg.msg_name = &peer_addr;
288*043036a2SApple OSS Distributions reply_msg.msg_namelen = sizeof(struct sockaddr_in);
289*043036a2SApple OSS Distributions reply_msg.msg_iov = &reply_iov;
290*043036a2SApple OSS Distributions reply_msg.msg_iovlen = 1;
291*043036a2SApple OSS Distributions reply_msg.msg_control = reply_control_space;
292*043036a2SApple OSS Distributions reply_msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
293*043036a2SApple OSS Distributions
294*043036a2SApple OSS Distributions send_in_pktinfo.ipi_addr.s_addr = 0;
295*043036a2SApple OSS Distributions if (by_ip_addr) {
296*043036a2SApple OSS Distributions send_in_pktinfo.ipi_ifindex = 0;
297*043036a2SApple OSS Distributions send_in_pktinfo.ipi_spec_dst.s_addr = recv_in_pktinfo.ipi_addr.s_addr;
298*043036a2SApple OSS Distributions } else {
299*043036a2SApple OSS Distributions send_in_pktinfo.ipi_ifindex = recv_in_pktinfo.ipi_ifindex;
300*043036a2SApple OSS Distributions send_in_pktinfo.ipi_spec_dst.s_addr = 0;
301*043036a2SApple OSS Distributions }
302*043036a2SApple OSS Distributions cmsg = CMSG_FIRSTHDR(&reply_msg);
303*043036a2SApple OSS Distributions cmsg->cmsg_level = IPPROTO_IP;
304*043036a2SApple OSS Distributions cmsg->cmsg_type = IP_PKTINFO;
305*043036a2SApple OSS Distributions cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
306*043036a2SApple OSS Distributions memcpy(CMSG_DATA(cmsg), &send_in_pktinfo, sizeof(struct in_pktinfo));
307*043036a2SApple OSS Distributions
308*043036a2SApple OSS Distributions ifname[0] = 0;
309*043036a2SApple OSS Distributions if_indextoname(send_in_pktinfo.ipi_ifindex, ifname);
310*043036a2SApple OSS Distributions inet_ntop(AF_INET, &send_in_pktinfo.ipi_spec_dst, spec_dst_str, sizeof(spec_dst_str));
311*043036a2SApple OSS Distributions inet_ntop(AF_INET, &send_in_pktinfo.ipi_addr, addr_str, sizeof(addr_str));
312*043036a2SApple OSS Distributions
313*043036a2SApple OSS Distributions T_LOG("sending %ld bytes to %s:%u with IP_PKTINFO ipi_ifindex: %u (%s) ipi_spec_dst: %s ipi_addr: %s",
314*043036a2SApple OSS Distributions retval, peer_addr_str, ntohs(peer_addr.sin_port),
315*043036a2SApple OSS Distributions send_in_pktinfo.ipi_ifindex, ifname, spec_dst_str, addr_str);
316*043036a2SApple OSS Distributions
317*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(retval = sendmsg(receiver_fd, &reply_msg, 0), NULL);
318*043036a2SApple OSS Distributions }
319*043036a2SApple OSS Distributions
320*043036a2SApple OSS Distributions static void
echo_and_check(int receiver_fd,bool by_ip_addr)321*043036a2SApple OSS Distributions echo_and_check(int receiver_fd, bool by_ip_addr)
322*043036a2SApple OSS Distributions {
323*043036a2SApple OSS Distributions socklen_t solen;
324*043036a2SApple OSS Distributions struct sockaddr_in before_sin = {};
325*043036a2SApple OSS Distributions char before_ifname[IFNAMSIZ];
326*043036a2SApple OSS Distributions u_int before_ifindex;
327*043036a2SApple OSS Distributions struct sockaddr_in after_sin = {};
328*043036a2SApple OSS Distributions char after_ifname[IFNAMSIZ];
329*043036a2SApple OSS Distributions u_int after_ifindex;
330*043036a2SApple OSS Distributions char before_addr_str[MAX_IPv4_STR_LEN];
331*043036a2SApple OSS Distributions char after_addr_str[MAX_IPv4_STR_LEN];
332*043036a2SApple OSS Distributions
333*043036a2SApple OSS Distributions T_LOG("%s(by_ip_addr: %s)", __func__, by_ip_addr ? "true" : "false");
334*043036a2SApple OSS Distributions
335*043036a2SApple OSS Distributions solen = sizeof(struct sockaddr_in);
336*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockname(receiver_fd, (struct sockaddr *)&before_sin, &solen), NULL);
337*043036a2SApple OSS Distributions inet_ntop(AF_INET, &before_sin.sin_addr, before_addr_str, sizeof(before_addr_str));
338*043036a2SApple OSS Distributions
339*043036a2SApple OSS Distributions solen = sizeof(before_ifname);
340*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockopt(receiver_fd, SOL_SOCKET, SO_BINDTODEVICE, before_ifname, &solen), NULL);
341*043036a2SApple OSS Distributions before_ifindex = if_nametoindex(before_ifname);
342*043036a2SApple OSS Distributions
343*043036a2SApple OSS Distributions echo(receiver_fd, by_ip_addr);
344*043036a2SApple OSS Distributions
345*043036a2SApple OSS Distributions solen = sizeof(struct sockaddr_in);
346*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockname(receiver_fd, (struct sockaddr *)&after_sin, &solen), NULL);
347*043036a2SApple OSS Distributions inet_ntop(AF_INET, &after_sin.sin_addr, after_addr_str, sizeof(after_addr_str));
348*043036a2SApple OSS Distributions
349*043036a2SApple OSS Distributions solen = sizeof(after_ifname);
350*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(getsockopt(receiver_fd, SOL_SOCKET, SO_BINDTODEVICE, after_ifname, &solen), NULL);
351*043036a2SApple OSS Distributions after_ifindex = if_nametoindex(after_ifname);
352*043036a2SApple OSS Distributions
353*043036a2SApple OSS Distributions
354*043036a2SApple OSS Distributions T_LOG("before bound to %s:%u over '%s'/%u", before_addr_str, ntohs(before_sin.sin_port), before_ifname, before_ifindex);
355*043036a2SApple OSS Distributions T_LOG("after bound to %s:%u over '%s'/%u", after_addr_str, ntohs(after_sin.sin_port), after_ifname, after_ifindex);
356*043036a2SApple OSS Distributions
357*043036a2SApple OSS Distributions T_ASSERT_EQ_USHORT(before_sin.sin_port, after_sin.sin_port, "same port");
358*043036a2SApple OSS Distributions T_ASSERT_EQ_UINT(before_sin.sin_addr.s_addr, after_sin.sin_addr.s_addr, "same IP address");
359*043036a2SApple OSS Distributions T_ASSERT_EQ_UINT(before_ifindex, after_ifindex, "same interface index");
360*043036a2SApple OSS Distributions }
361*043036a2SApple OSS Distributions
362*043036a2SApple OSS Distributions static void
do_test_ip_pktinfo(bool bind_to_device,bool bind_to_port,in_addr_t bind_to_addr)363*043036a2SApple OSS Distributions do_test_ip_pktinfo(bool bind_to_device, bool bind_to_port, in_addr_t bind_to_addr)
364*043036a2SApple OSS Distributions {
365*043036a2SApple OSS Distributions int receiver_fd;
366*043036a2SApple OSS Distributions in_port_t receiver_port = 0;
367*043036a2SApple OSS Distributions int sender_fd;
368*043036a2SApple OSS Distributions ssize_t retval;
369*043036a2SApple OSS Distributions
370*043036a2SApple OSS Distributions init();
371*043036a2SApple OSS Distributions
372*043036a2SApple OSS Distributions receiver_fd = setup_receiver(bind_to_device ? ifname1 : NULL,
373*043036a2SApple OSS Distributions bind_to_port,
374*043036a2SApple OSS Distributions bind_to_addr ? S_feth_pairs->list->one.ip.s_addr : INADDR_ANY,
375*043036a2SApple OSS Distributions &receiver_port);
376*043036a2SApple OSS Distributions sender_fd = setup_sender(ifname2, S_feth_pairs->list->one.ip.s_addr, receiver_port);
377*043036a2SApple OSS Distributions
378*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(retval = send(sender_fd, data, strlen(data) + 1, 0), NULL);
379*043036a2SApple OSS Distributions echo_and_check(receiver_fd, true);
380*043036a2SApple OSS Distributions
381*043036a2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(retval = send(sender_fd, data, strlen(data) + 1, 0), NULL);
382*043036a2SApple OSS Distributions echo_and_check(receiver_fd, false);
383*043036a2SApple OSS Distributions
384*043036a2SApple OSS Distributions close(sender_fd);
385*043036a2SApple OSS Distributions close(receiver_fd);
386*043036a2SApple OSS Distributions
387*043036a2SApple OSS Distributions success = true;
388*043036a2SApple OSS Distributions }
389*043036a2SApple OSS Distributions
390*043036a2SApple OSS Distributions
391*043036a2SApple OSS Distributions T_DECL(ip_pktinfo_010, "IP_PTKINFO bind_to_device=false bind_to_port=true bind_to_addr=false")
392*043036a2SApple OSS Distributions {
393*043036a2SApple OSS Distributions do_test_ip_pktinfo(false, true, false);
394*043036a2SApple OSS Distributions }
395*043036a2SApple OSS Distributions
396*043036a2SApple OSS Distributions T_DECL(ip_pktinfo_011, "IP_PTKINFO bind_to_device=false bind_to_port=true bind_to_addr=true")
397*043036a2SApple OSS Distributions {
398*043036a2SApple OSS Distributions do_test_ip_pktinfo(false, true, true);
399*043036a2SApple OSS Distributions }
400*043036a2SApple OSS Distributions
401*043036a2SApple OSS Distributions T_DECL(ip_pktinfo_110, "IP_PTKINFO bind_to_device=true bind_to_port=true bind_to_addr=false")
402*043036a2SApple OSS Distributions {
403*043036a2SApple OSS Distributions do_test_ip_pktinfo(true, true, false);
404*043036a2SApple OSS Distributions }
405*043036a2SApple OSS Distributions
406*043036a2SApple OSS Distributions T_DECL(ip_pktinfo_111, "IP_PTKINFO bind_to_device=true bind_to_port=true bind_to_addr=true")
407*043036a2SApple OSS Distributions {
408*043036a2SApple OSS Distributions do_test_ip_pktinfo(true, true, true);
409*043036a2SApple OSS Distributions }
410