xref: /xnu-12377.41.6/tests/bpf_write_batch.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions /*
2*bbb1b6f9SApple OSS Distributions  * Copyright (c) 2023-2024 Apple Inc. All rights reserved.
3*bbb1b6f9SApple OSS Distributions  *
4*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*bbb1b6f9SApple OSS Distributions  *
6*bbb1b6f9SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*bbb1b6f9SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*bbb1b6f9SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*bbb1b6f9SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*bbb1b6f9SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*bbb1b6f9SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*bbb1b6f9SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*bbb1b6f9SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*bbb1b6f9SApple OSS Distributions  *
15*bbb1b6f9SApple OSS Distributions  * Please obtain a copy of the License at
16*bbb1b6f9SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*bbb1b6f9SApple OSS Distributions  *
18*bbb1b6f9SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*bbb1b6f9SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*bbb1b6f9SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*bbb1b6f9SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*bbb1b6f9SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*bbb1b6f9SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*bbb1b6f9SApple OSS Distributions  * limitations under the License.
25*bbb1b6f9SApple OSS Distributions  *
26*bbb1b6f9SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*bbb1b6f9SApple OSS Distributions  */
28*bbb1b6f9SApple OSS Distributions 
29*bbb1b6f9SApple OSS Distributions #include <darwintest.h>
30*bbb1b6f9SApple OSS Distributions 
31*bbb1b6f9SApple OSS Distributions #include <sys/ioctl.h>
32*bbb1b6f9SApple OSS Distributions #include <sys/sysctl.h>
33*bbb1b6f9SApple OSS Distributions #include <sys/uio.h>
34*bbb1b6f9SApple OSS Distributions 
35*bbb1b6f9SApple OSS Distributions #include <net/if.h>
36*bbb1b6f9SApple OSS Distributions #include <net/if_arp.h>
37*bbb1b6f9SApple OSS Distributions #include <net/if_fake_var.h>
38*bbb1b6f9SApple OSS Distributions #include <net/bpf.h>
39*bbb1b6f9SApple OSS Distributions #include <net/ethernet.h>
40*bbb1b6f9SApple OSS Distributions 
41*bbb1b6f9SApple OSS Distributions #include <netinet/ip.h>
42*bbb1b6f9SApple OSS Distributions 
43*bbb1b6f9SApple OSS Distributions #include <stdlib.h>
44*bbb1b6f9SApple OSS Distributions #include <string.h>
45*bbb1b6f9SApple OSS Distributions #include <strings.h>
46*bbb1b6f9SApple OSS Distributions 
47*bbb1b6f9SApple OSS Distributions #include "net_test_lib.h"
48*bbb1b6f9SApple OSS Distributions #include "bpflib.h"
49*bbb1b6f9SApple OSS Distributions #include "in_cksum.h"
50*bbb1b6f9SApple OSS Distributions 
51*bbb1b6f9SApple OSS Distributions T_GLOBAL_META(
52*bbb1b6f9SApple OSS Distributions 	T_META_NAMESPACE("xnu.net"),
53*bbb1b6f9SApple OSS Distributions 	T_META_ASROOT(true),
54*bbb1b6f9SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
55*bbb1b6f9SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("networking"),
56*bbb1b6f9SApple OSS Distributions 	T_META_CHECK_LEAKS(false));
57*bbb1b6f9SApple OSS Distributions 
58*bbb1b6f9SApple OSS Distributions #define MAXBUF 32
59*bbb1b6f9SApple OSS Distributions static void
HexDump(void * data,size_t len)60*bbb1b6f9SApple OSS Distributions HexDump(void *data, size_t len)
61*bbb1b6f9SApple OSS Distributions {
62*bbb1b6f9SApple OSS Distributions 	size_t i, j, k;
63*bbb1b6f9SApple OSS Distributions 	unsigned char *ptr = (unsigned char *)data;
64*bbb1b6f9SApple OSS Distributions 	unsigned char buf[3 * MAXBUF + 1];
65*bbb1b6f9SApple OSS Distributions 
66*bbb1b6f9SApple OSS Distributions 	for (i = 0; i < len; i += MAXBUF) {
67*bbb1b6f9SApple OSS Distributions 		for (j = i, k = 0; j < i + MAXBUF && j < len; j++) {
68*bbb1b6f9SApple OSS Distributions 			unsigned char msnbl = ptr[j] >> 4;
69*bbb1b6f9SApple OSS Distributions 			unsigned char lsnbl = ptr[j] & 0x0f;
70*bbb1b6f9SApple OSS Distributions 
71*bbb1b6f9SApple OSS Distributions 			buf[k++] = msnbl < 10 ? msnbl + '0' : msnbl + 'a' - 10;
72*bbb1b6f9SApple OSS Distributions 			buf[k++] = lsnbl < 10 ? lsnbl + '0' : lsnbl + 'a' - 10;
73*bbb1b6f9SApple OSS Distributions 			if ((j % 2) == 1) {
74*bbb1b6f9SApple OSS Distributions 				buf[k++] = ' ';
75*bbb1b6f9SApple OSS Distributions 			}
76*bbb1b6f9SApple OSS Distributions 			if ((j % MAXBUF) == MAXBUF - 1) {
77*bbb1b6f9SApple OSS Distributions 				buf[k++] = ' ';
78*bbb1b6f9SApple OSS Distributions 			}
79*bbb1b6f9SApple OSS Distributions 		}
80*bbb1b6f9SApple OSS Distributions 		buf[k] = 0;
81*bbb1b6f9SApple OSS Distributions 		T_LOG("%5zd: %s\n", i, buf);
82*bbb1b6f9SApple OSS Distributions 	}
83*bbb1b6f9SApple OSS Distributions }
84*bbb1b6f9SApple OSS Distributions 
85*bbb1b6f9SApple OSS Distributions static char ifname1[IF_NAMESIZE];
86*bbb1b6f9SApple OSS Distributions static char ifname2[IF_NAMESIZE];
87*bbb1b6f9SApple OSS Distributions static int default_fake_max_mtu = 0;
88*bbb1b6f9SApple OSS Distributions 
89*bbb1b6f9SApple OSS Distributions static void
cleanup(void)90*bbb1b6f9SApple OSS Distributions cleanup(void)
91*bbb1b6f9SApple OSS Distributions {
92*bbb1b6f9SApple OSS Distributions 	if (ifname1[0] != '\0') {
93*bbb1b6f9SApple OSS Distributions 		(void)ifnet_destroy(ifname1, false);
94*bbb1b6f9SApple OSS Distributions 		T_LOG("ifnet_destroy %s", ifname1);
95*bbb1b6f9SApple OSS Distributions 	}
96*bbb1b6f9SApple OSS Distributions 	if (ifname2[0] != '\0') {
97*bbb1b6f9SApple OSS Distributions 		(void)ifnet_destroy(ifname2, false);
98*bbb1b6f9SApple OSS Distributions 		T_LOG("ifnet_destroy %s", ifname2);
99*bbb1b6f9SApple OSS Distributions 	}
100*bbb1b6f9SApple OSS Distributions 
101*bbb1b6f9SApple OSS Distributions 	if (default_fake_max_mtu != 0) {
102*bbb1b6f9SApple OSS Distributions 		T_LOG("sysctl net.link.fake.max_mtu=%d", default_fake_max_mtu);
103*bbb1b6f9SApple OSS Distributions 		(void) sysctlbyname("net.link.fake.max_mtu", NULL, NULL, &default_fake_max_mtu, sizeof(int));
104*bbb1b6f9SApple OSS Distributions 	}
105*bbb1b6f9SApple OSS Distributions }
106*bbb1b6f9SApple OSS Distributions 
107*bbb1b6f9SApple OSS Distributions static void
init(int mtu)108*bbb1b6f9SApple OSS Distributions init(int mtu)
109*bbb1b6f9SApple OSS Distributions {
110*bbb1b6f9SApple OSS Distributions 	T_ATEND(cleanup);
111*bbb1b6f9SApple OSS Distributions 
112*bbb1b6f9SApple OSS Distributions 	if (mtu > 0) {
113*bbb1b6f9SApple OSS Distributions 		size_t oldlen = sizeof(int);
114*bbb1b6f9SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(sysctlbyname("net.link.fake.max_mtu", &default_fake_max_mtu, &oldlen, &mtu, sizeof(int)),
115*bbb1b6f9SApple OSS Distributions 		    "sysctl net.link.fake.max_mtu %d -> %d", default_fake_max_mtu, mtu);
116*bbb1b6f9SApple OSS Distributions 	}
117*bbb1b6f9SApple OSS Distributions }
118*bbb1b6f9SApple OSS Distributions 
119*bbb1b6f9SApple OSS Distributions static int
setup_feth_pair(int mtu)120*bbb1b6f9SApple OSS Distributions setup_feth_pair(int mtu)
121*bbb1b6f9SApple OSS Distributions {
122*bbb1b6f9SApple OSS Distributions 	int error = 0;
123*bbb1b6f9SApple OSS Distributions 
124*bbb1b6f9SApple OSS Distributions 	strlcpy(ifname1, FETH_NAME, sizeof(ifname1));
125*bbb1b6f9SApple OSS Distributions 	error = ifnet_create_2(ifname1, sizeof(ifname1));
126*bbb1b6f9SApple OSS Distributions 	if (error != 0) {
127*bbb1b6f9SApple OSS Distributions 		ifname1[0] = '\0';
128*bbb1b6f9SApple OSS Distributions 		goto done;
129*bbb1b6f9SApple OSS Distributions 	}
130*bbb1b6f9SApple OSS Distributions 	T_LOG("created %s", ifname1);
131*bbb1b6f9SApple OSS Distributions 
132*bbb1b6f9SApple OSS Distributions 	strlcpy(ifname2, FETH_NAME, sizeof(ifname2));
133*bbb1b6f9SApple OSS Distributions 	error = ifnet_create_2(ifname2, sizeof(ifname2));
134*bbb1b6f9SApple OSS Distributions 	if (error != 0) {
135*bbb1b6f9SApple OSS Distributions 		ifname2[0] = '\0';
136*bbb1b6f9SApple OSS Distributions 		goto done;
137*bbb1b6f9SApple OSS Distributions 	}
138*bbb1b6f9SApple OSS Distributions 	T_LOG("created %s", ifname2);
139*bbb1b6f9SApple OSS Distributions 
140*bbb1b6f9SApple OSS Distributions 	ifnet_attach_ip(ifname1);
141*bbb1b6f9SApple OSS Distributions 
142*bbb1b6f9SApple OSS Distributions 	fake_set_peer(ifname1, ifname2);
143*bbb1b6f9SApple OSS Distributions 	if (mtu != 0) {
144*bbb1b6f9SApple OSS Distributions 		ifnet_set_mtu(ifname1, mtu);
145*bbb1b6f9SApple OSS Distributions 		ifnet_set_mtu(ifname2, mtu);
146*bbb1b6f9SApple OSS Distributions 	}
147*bbb1b6f9SApple OSS Distributions done:
148*bbb1b6f9SApple OSS Distributions 	return error;
149*bbb1b6f9SApple OSS Distributions }
150*bbb1b6f9SApple OSS Distributions 
151*bbb1b6f9SApple OSS Distributions static int
create_bpf_on_interface(const char * ifname,int * out_fd,int * out_bdlen,u_int write_size_max)152*bbb1b6f9SApple OSS Distributions create_bpf_on_interface(const char *ifname, int *out_fd, int *out_bdlen, u_int write_size_max)
153*bbb1b6f9SApple OSS Distributions {
154*bbb1b6f9SApple OSS Distributions 	int bpf_fd = -1;
155*bbb1b6f9SApple OSS Distributions 	int error = 0;
156*bbb1b6f9SApple OSS Distributions 	int bdlen = 0;
157*bbb1b6f9SApple OSS Distributions 	u_int value;
158*bbb1b6f9SApple OSS Distributions 
159*bbb1b6f9SApple OSS Distributions 	bpf_fd = bpf_new();
160*bbb1b6f9SApple OSS Distributions 	if (bpf_fd < 0) {
161*bbb1b6f9SApple OSS Distributions 		error = errno;
162*bbb1b6f9SApple OSS Distributions 		T_LOG("bpf_new");
163*bbb1b6f9SApple OSS Distributions 		goto done;
164*bbb1b6f9SApple OSS Distributions 	}
165*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_blen(bpf_fd, 128 * 1024), NULL);
166*bbb1b6f9SApple OSS Distributions 
167*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_get_blen(bpf_fd, &bdlen), NULL);
168*bbb1b6f9SApple OSS Distributions 
169*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_immediate(bpf_fd, 1), NULL);
170*bbb1b6f9SApple OSS Distributions 
171*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_setif(bpf_fd, ifname), "bpf set if %s",
172*bbb1b6f9SApple OSS Distributions 	    ifname1);
173*bbb1b6f9SApple OSS Distributions 
174*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_see_sent(bpf_fd, 1), NULL);
175*bbb1b6f9SApple OSS Distributions 
176*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_header_complete(bpf_fd, 1), NULL);
177*bbb1b6f9SApple OSS Distributions 
178*bbb1b6f9SApple OSS Distributions #ifdef BIOCSWRITEMAX
179*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_write_size_max(bpf_fd, write_size_max), NULL);
180*bbb1b6f9SApple OSS Distributions 
181*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_get_write_size_max(bpf_fd, &value), NULL);
182*bbb1b6f9SApple OSS Distributions 
183*bbb1b6f9SApple OSS Distributions 	T_LOG("write_size_max %u %s value %u", write_size_max, write_size_max != value ? "!=" : "==", value);
184*bbb1b6f9SApple OSS Distributions #else
185*bbb1b6f9SApple OSS Distributions 	if (write_size_max > 0) {
186*bbb1b6f9SApple OSS Distributions 		T_SKIP("BIOCSWRITEMAX not supported");
187*bbb1b6f9SApple OSS Distributions 	}
188*bbb1b6f9SApple OSS Distributions #endif
189*bbb1b6f9SApple OSS Distributions 
190*bbb1b6f9SApple OSS Distributions #ifdef BIOCSBATCHWRITE
191*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_batch_write(bpf_fd, 1), NULL);
192*bbb1b6f9SApple OSS Distributions 
193*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_get_batch_write(bpf_fd, &value), NULL);
194*bbb1b6f9SApple OSS Distributions 
195*bbb1b6f9SApple OSS Distributions 	T_LOG("batch_write %u %s 1", value, value != 1 ? "!=" : "==");
196*bbb1b6f9SApple OSS Distributions #else
197*bbb1b6f9SApple OSS Distributions 	T_SKIP("BIOCSBATCHWRITE not supported");
198*bbb1b6f9SApple OSS Distributions #endif
199*bbb1b6f9SApple OSS Distributions 
200*bbb1b6f9SApple OSS Distributions 	struct timeval five_seconds = { .tv_sec = 5, .tv_usec = 0 };
201*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(bpf_set_timeout(bpf_fd, &five_seconds), NULL);
202*bbb1b6f9SApple OSS Distributions 
203*bbb1b6f9SApple OSS Distributions done:
204*bbb1b6f9SApple OSS Distributions 	*out_bdlen = bdlen;
205*bbb1b6f9SApple OSS Distributions 	*out_fd = bpf_fd;
206*bbb1b6f9SApple OSS Distributions 	return error;
207*bbb1b6f9SApple OSS Distributions }
208*bbb1b6f9SApple OSS Distributions 
209*bbb1b6f9SApple OSS Distributions static void
make_bootp_packet(struct iovec * iov,u_int ip_len,int id)210*bbb1b6f9SApple OSS Distributions make_bootp_packet(struct iovec *iov, u_int ip_len, int id)
211*bbb1b6f9SApple OSS Distributions {
212*bbb1b6f9SApple OSS Distributions 	u_int payload_len;
213*bbb1b6f9SApple OSS Distributions 
214*bbb1b6f9SApple OSS Distributions 	if (ip_len == 0) {
215*bbb1b6f9SApple OSS Distributions 		payload_len = (u_int)sizeof(dhcp_min_payload);
216*bbb1b6f9SApple OSS Distributions 	} else {
217*bbb1b6f9SApple OSS Distributions 		T_ASSERT_GE((size_t)ip_len, sizeof(struct ip) + sizeof(struct udphdr) + sizeof(dhcp_min_payload),
218*bbb1b6f9SApple OSS Distributions 		    "ip_len");
219*bbb1b6f9SApple OSS Distributions 		payload_len = ip_len - (sizeof(struct ip) + sizeof(struct udphdr));
220*bbb1b6f9SApple OSS Distributions 	}
221*bbb1b6f9SApple OSS Distributions 
222*bbb1b6f9SApple OSS Distributions 	struct ether_addr src_eaddr = { 0 };
223*bbb1b6f9SApple OSS Distributions 	ifnet_get_lladdr(ifname1, &src_eaddr);
224*bbb1b6f9SApple OSS Distributions 
225*bbb1b6f9SApple OSS Distributions 	struct in_addr src_ip = { .s_addr = INADDR_ANY };
226*bbb1b6f9SApple OSS Distributions 	uint16_t src_port = 68;
227*bbb1b6f9SApple OSS Distributions 
228*bbb1b6f9SApple OSS Distributions 	struct ether_addr dst_eaddr = { 0 };
229*bbb1b6f9SApple OSS Distributions 	memset(dst_eaddr.octet, 255, ETHER_ADDR_LEN);
230*bbb1b6f9SApple OSS Distributions 
231*bbb1b6f9SApple OSS Distributions 	struct in_addr dst_ip = { .s_addr = INADDR_BROADCAST };
232*bbb1b6f9SApple OSS Distributions 
233*bbb1b6f9SApple OSS Distributions 	uint16_t dst_port = 67;
234*bbb1b6f9SApple OSS Distributions 
235*bbb1b6f9SApple OSS Distributions 	void *payload = calloc(1, payload_len);
236*bbb1b6f9SApple OSS Distributions 
237*bbb1b6f9SApple OSS Distributions 	make_dhcp_payload((dhcp_min_payload_t)payload, &src_eaddr);
238*bbb1b6f9SApple OSS Distributions 
239*bbb1b6f9SApple OSS Distributions 	struct bootp *dhcp = (struct bootp *)payload;
240*bbb1b6f9SApple OSS Distributions 	dhcp->bp_xid = (uint32_t)id;
241*bbb1b6f9SApple OSS Distributions 
242*bbb1b6f9SApple OSS Distributions 	u_int pkt_size = ETHER_HDR_LEN + IP_MAXPACKET;
243*bbb1b6f9SApple OSS Distributions 	unsigned char *pkt = calloc(1, pkt_size);
244*bbb1b6f9SApple OSS Distributions 
245*bbb1b6f9SApple OSS Distributions 	u_int frame_length = ethernet_udp4_frame_populate((void *)pkt,
246*bbb1b6f9SApple OSS Distributions 	    pkt_size,
247*bbb1b6f9SApple OSS Distributions 	    &src_eaddr,
248*bbb1b6f9SApple OSS Distributions 	    src_ip,
249*bbb1b6f9SApple OSS Distributions 	    src_port,
250*bbb1b6f9SApple OSS Distributions 	    &dst_eaddr,
251*bbb1b6f9SApple OSS Distributions 	    dst_ip,
252*bbb1b6f9SApple OSS Distributions 	    dst_port,
253*bbb1b6f9SApple OSS Distributions 	    payload,
254*bbb1b6f9SApple OSS Distributions 	    payload_len);
255*bbb1b6f9SApple OSS Distributions 
256*bbb1b6f9SApple OSS Distributions 	T_ASSERT_EQ(sizeof(struct bpf_hdr), BPF_WORDALIGN(sizeof(struct bpf_hdr)), "bpfhdr.bh_hdrlen == BPF_WORDALIGN(sizeof(struct bpf_hdr))");
257*bbb1b6f9SApple OSS Distributions 
258*bbb1b6f9SApple OSS Distributions 	struct bpf_hdr bpfhdr = { 0 };
259*bbb1b6f9SApple OSS Distributions 	bpfhdr.bh_caplen = frame_length;
260*bbb1b6f9SApple OSS Distributions 	bpfhdr.bh_datalen = frame_length;
261*bbb1b6f9SApple OSS Distributions 	bpfhdr.bh_hdrlen = sizeof(struct bpf_hdr);
262*bbb1b6f9SApple OSS Distributions 
263*bbb1b6f9SApple OSS Distributions 	iov->iov_len = BPF_WORDALIGN(bpfhdr.bh_hdrlen + frame_length);
264*bbb1b6f9SApple OSS Distributions 	iov->iov_base = calloc(1, iov->iov_len);
265*bbb1b6f9SApple OSS Distributions 
266*bbb1b6f9SApple OSS Distributions 	T_LOG("iov_len %lu bh_hdrlen %u frame_length %u ip_len %u payload_len %u",
267*bbb1b6f9SApple OSS Distributions 	    iov->iov_len, bpfhdr.bh_hdrlen, frame_length, ip_len, payload_len);
268*bbb1b6f9SApple OSS Distributions 
269*bbb1b6f9SApple OSS Distributions 	bcopy(&bpfhdr, iov->iov_base, bpfhdr.bh_hdrlen);
270*bbb1b6f9SApple OSS Distributions 	bcopy(pkt, (char *)iov->iov_base + bpfhdr.bh_hdrlen, frame_length);
271*bbb1b6f9SApple OSS Distributions 
272*bbb1b6f9SApple OSS Distributions 	free(pkt);
273*bbb1b6f9SApple OSS Distributions 	free(payload);
274*bbb1b6f9SApple OSS Distributions }
275*bbb1b6f9SApple OSS Distributions 
276*bbb1b6f9SApple OSS Distributions static void
do_bpf_write_batch(int count,const char * ifname,u_int ip_len,bool expect_success,u_int write_size_max)277*bbb1b6f9SApple OSS Distributions do_bpf_write_batch(int count, const char *ifname, u_int ip_len, bool expect_success, u_int write_size_max)
278*bbb1b6f9SApple OSS Distributions {
279*bbb1b6f9SApple OSS Distributions 	int bpf_fd = -1;
280*bbb1b6f9SApple OSS Distributions 	int bdlen = 0;
281*bbb1b6f9SApple OSS Distributions 	struct iovec *iovs = NULL;
282*bbb1b6f9SApple OSS Distributions 	int i;
283*bbb1b6f9SApple OSS Distributions 
284*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_ZERO(create_bpf_on_interface(ifname, &bpf_fd, &bdlen, write_size_max), NULL);
285*bbb1b6f9SApple OSS Distributions 	T_LOG("bpf bdlen %d", bdlen);
286*bbb1b6f9SApple OSS Distributions 
287*bbb1b6f9SApple OSS Distributions 	/*
288*bbb1b6f9SApple OSS Distributions 	 * Allocate an iovec for each packet that contains the BPF header + the data
289*bbb1b6f9SApple OSS Distributions 	 */
290*bbb1b6f9SApple OSS Distributions 	iovs = calloc((size_t)count, sizeof(struct iovec));
291*bbb1b6f9SApple OSS Distributions 
292*bbb1b6f9SApple OSS Distributions 	ssize_t total_len = 0;
293*bbb1b6f9SApple OSS Distributions 	for (i = 0; i < count; i++) {
294*bbb1b6f9SApple OSS Distributions 		make_bootp_packet(&iovs[i], ip_len, i + 1);
295*bbb1b6f9SApple OSS Distributions 		total_len += iovs[i].iov_len;
296*bbb1b6f9SApple OSS Distributions 
297*bbb1b6f9SApple OSS Distributions 		struct bpf_hdr *h0 = (struct bpf_hdr *)iovs[i].iov_base;;
298*bbb1b6f9SApple OSS Distributions 
299*bbb1b6f9SApple OSS Distributions 		T_LOG("tv_sec %u tv_usec %u caplen %u datalen %u hdrlen %u",
300*bbb1b6f9SApple OSS Distributions 		    h0->bh_tstamp.tv_sec, h0->bh_tstamp.tv_usec,
301*bbb1b6f9SApple OSS Distributions 		    h0->bh_caplen, h0->bh_datalen, h0->bh_hdrlen);
302*bbb1b6f9SApple OSS Distributions 
303*bbb1b6f9SApple OSS Distributions 		HexDump(iovs[i].iov_base, MIN((size_t)iovs[i].iov_len, 512));
304*bbb1b6f9SApple OSS Distributions 
305*bbb1b6f9SApple OSS Distributions 		T_ASSERT_EQ((int)(iovs[i].iov_len % BPF_ALIGNMENT), 0, "iovs[i].iov_len %% BPF_ALIGNMENT == 0");
306*bbb1b6f9SApple OSS Distributions 	}
307*bbb1b6f9SApple OSS Distributions 	T_LOG("total_len %ld", total_len);
308*bbb1b6f9SApple OSS Distributions 
309*bbb1b6f9SApple OSS Distributions 	ssize_t nwritten;
310*bbb1b6f9SApple OSS Distributions 	nwritten = writev(bpf_fd, iovs, count);
311*bbb1b6f9SApple OSS Distributions 
312*bbb1b6f9SApple OSS Distributions 	T_LOG("bpf write returned %ld", nwritten);
313*bbb1b6f9SApple OSS Distributions 
314*bbb1b6f9SApple OSS Distributions 	if (expect_success) {
315*bbb1b6f9SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(nwritten, "write bpf");
316*bbb1b6f9SApple OSS Distributions 	} else {
317*bbb1b6f9SApple OSS Distributions 		T_ASSERT_POSIX_FAILURE(nwritten, EMSGSIZE, "write bpf");
318*bbb1b6f9SApple OSS Distributions 		goto done;
319*bbb1b6f9SApple OSS Distributions 	}
320*bbb1b6f9SApple OSS Distributions 
321*bbb1b6f9SApple OSS Distributions 	T_LOG("bpf written %ld bytes over %lu", nwritten, total_len);
322*bbb1b6f9SApple OSS Distributions 
323*bbb1b6f9SApple OSS Distributions 	T_ASSERT_GE((size_t)nwritten, iovs[0].iov_len, "nwritten %lu >= iovs[0].iov_len %lu", nwritten, iovs[0].iov_len);
324*bbb1b6f9SApple OSS Distributions 
325*bbb1b6f9SApple OSS Distributions 	/*
326*bbb1b6f9SApple OSS Distributions 	 * Give 100 ms for the packets to be captured
327*bbb1b6f9SApple OSS Distributions 	 */
328*bbb1b6f9SApple OSS Distributions 	usleep(100000);
329*bbb1b6f9SApple OSS Distributions 
330*bbb1b6f9SApple OSS Distributions 	/*
331*bbb1b6f9SApple OSS Distributions 	 * Read the batch and verify the content matches what we just sent.
332*bbb1b6f9SApple OSS Distributions 	 */
333*bbb1b6f9SApple OSS Distributions 	unsigned char *buffer = calloc(1, (size_t)bdlen);
334*bbb1b6f9SApple OSS Distributions 	T_ASSERT_NOTNULL(buffer, "malloc()");
335*bbb1b6f9SApple OSS Distributions 
336*bbb1b6f9SApple OSS Distributions 	ssize_t nread = read(bpf_fd, buffer, (size_t)bdlen);
337*bbb1b6f9SApple OSS Distributions 
338*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(nread, "read bpf");
339*bbb1b6f9SApple OSS Distributions 
340*bbb1b6f9SApple OSS Distributions 	T_LOG("bpf read %ld bytes", nread);
341*bbb1b6f9SApple OSS Distributions 
342*bbb1b6f9SApple OSS Distributions 	/*
343*bbb1b6f9SApple OSS Distributions 	 * We need at least the BPF header
344*bbb1b6f9SApple OSS Distributions 	 */
345*bbb1b6f9SApple OSS Distributions 	T_ASSERT_GT((size_t)nread, sizeof(sizeof(struct bpf_hdr)), NULL);
346*bbb1b6f9SApple OSS Distributions 
347*bbb1b6f9SApple OSS Distributions 	unsigned char *bp = buffer;
348*bbb1b6f9SApple OSS Distributions 	unsigned char *ep = buffer + nread;
349*bbb1b6f9SApple OSS Distributions 
350*bbb1b6f9SApple OSS Distributions 	for (i = 0; i < count && bp < ep; i++) {
351*bbb1b6f9SApple OSS Distributions 		struct bpf_hdr *hp = (struct bpf_hdr *)(void *)bp;
352*bbb1b6f9SApple OSS Distributions 
353*bbb1b6f9SApple OSS Distributions 		T_LOG("tv_sec %u tv_usec %u caplen %u datalen %u hdrlen %u",
354*bbb1b6f9SApple OSS Distributions 		    hp->bh_tstamp.tv_sec, hp->bh_tstamp.tv_usec,
355*bbb1b6f9SApple OSS Distributions 		    hp->bh_caplen, hp->bh_datalen, hp->bh_hdrlen);
356*bbb1b6f9SApple OSS Distributions 
357*bbb1b6f9SApple OSS Distributions 		HexDump(bp, MIN((size_t)BPF_WORDALIGN(hp->bh_hdrlen + hp->bh_caplen), 512));
358*bbb1b6f9SApple OSS Distributions 
359*bbb1b6f9SApple OSS Distributions 		/*
360*bbb1b6f9SApple OSS Distributions 		 * Note: The following will fail if there is parasitic traffic and that should not happen over feth
361*bbb1b6f9SApple OSS Distributions 		 */
362*bbb1b6f9SApple OSS Distributions 		unsigned char *p0 = iovs[i].iov_base;
363*bbb1b6f9SApple OSS Distributions 		struct bpf_hdr *h0 = (struct bpf_hdr *)iovs[i].iov_base;;
364*bbb1b6f9SApple OSS Distributions 
365*bbb1b6f9SApple OSS Distributions 		T_ASSERT_EQ(h0->bh_caplen, hp->bh_caplen, "h0->bh_caplen %d == hp->bh_caplen %d", h0->bh_caplen, hp->bh_caplen);
366*bbb1b6f9SApple OSS Distributions 		T_ASSERT_EQ(h0->bh_datalen, hp->bh_datalen, "h0->bh_datalen %d == hp->bh_datalen %d", h0->bh_datalen, hp->bh_datalen);
367*bbb1b6f9SApple OSS Distributions 
368*bbb1b6f9SApple OSS Distributions 		T_ASSERT_EQ_INT(bcmp(h0->bh_hdrlen + p0, hp->bh_hdrlen + bp, hp->bh_caplen), 0, "bpf read same bytes as written iov %d", i);
369*bbb1b6f9SApple OSS Distributions 
370*bbb1b6f9SApple OSS Distributions 		bp += BPF_WORDALIGN(hp->bh_hdrlen + hp->bh_caplen);
371*bbb1b6f9SApple OSS Distributions 	}
372*bbb1b6f9SApple OSS Distributions 
373*bbb1b6f9SApple OSS Distributions 	if (buffer != NULL) {
374*bbb1b6f9SApple OSS Distributions 		free(buffer);
375*bbb1b6f9SApple OSS Distributions 	}
376*bbb1b6f9SApple OSS Distributions done:
377*bbb1b6f9SApple OSS Distributions 	if (bpf_fd != -1) {
378*bbb1b6f9SApple OSS Distributions 		close(bpf_fd);
379*bbb1b6f9SApple OSS Distributions 	}
380*bbb1b6f9SApple OSS Distributions }
381*bbb1b6f9SApple OSS Distributions 
382*bbb1b6f9SApple OSS Distributions static void
test_bpf_write_batch(int count,u_int data_len,int mtu,bool expect_success,u_int write_size_max)383*bbb1b6f9SApple OSS Distributions test_bpf_write_batch(int count, u_int data_len, int mtu, bool expect_success, u_int write_size_max)
384*bbb1b6f9SApple OSS Distributions {
385*bbb1b6f9SApple OSS Distributions 	init(mtu);
386*bbb1b6f9SApple OSS Distributions 
387*bbb1b6f9SApple OSS Distributions 	T_ASSERT_POSIX_ZERO(setup_feth_pair(mtu), NULL);
388*bbb1b6f9SApple OSS Distributions 
389*bbb1b6f9SApple OSS Distributions 	do_bpf_write_batch(count, ifname1, data_len, expect_success, write_size_max);
390*bbb1b6f9SApple OSS Distributions }
391*bbb1b6f9SApple OSS Distributions 
392*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_dhcp, "BPF write DHCP feth MTU 1500")
393*bbb1b6f9SApple OSS Distributions {
394*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(1, 0, 1500, true, 0);
395*bbb1b6f9SApple OSS Distributions }
396*bbb1b6f9SApple OSS Distributions 
397*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_dhcp_x2, "BPF write DHCP feth MTU 1500 x 2")
398*bbb1b6f9SApple OSS Distributions {
399*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(2, 0, 1500, true, 0);
400*bbb1b6f9SApple OSS Distributions }
401*bbb1b6f9SApple OSS Distributions 
402*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_dhcp_x3, "BPF write DHCP feth MTU 1500 x 3")
403*bbb1b6f9SApple OSS Distributions {
404*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(3, 0, 1500, true, 0);
405*bbb1b6f9SApple OSS Distributions }
406*bbb1b6f9SApple OSS Distributions 
407*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_1020, "BPF write 1020 feth MTU 1500 x 2")
408*bbb1b6f9SApple OSS Distributions {
409*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(2, 1020, 1500, true, 0);
410*bbb1b6f9SApple OSS Distributions }
411*bbb1b6f9SApple OSS Distributions 
412*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_1021, "BPF write 1021 feth MTU 1500 x 2")
413*bbb1b6f9SApple OSS Distributions {
414*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(2, 1021, 1500, true, 0);
415*bbb1b6f9SApple OSS Distributions }
416*bbb1b6f9SApple OSS Distributions 
417*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_1022, "BPF write 1022 feth MTU 1500 x 2")
418*bbb1b6f9SApple OSS Distributions {
419*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(2, 1022, 1500, true, 0);
420*bbb1b6f9SApple OSS Distributions }
421*bbb1b6f9SApple OSS Distributions 
422*bbb1b6f9SApple OSS Distributions T_DECL(bpf_write_batch_1023, "BPF write 1023 feth MTU 1500 x2 ")
423*bbb1b6f9SApple OSS Distributions {
424*bbb1b6f9SApple OSS Distributions 	test_bpf_write_batch(2, 1023, 1500, true, 0);
425*bbb1b6f9SApple OSS Distributions }
426