xref: /openbmc/linux/tools/testing/selftests/net/mptcp/mptcp_sockopt.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1ce997912SFlorian Westphal // SPDX-License-Identifier: GPL-2.0
2ce997912SFlorian Westphal 
3ce997912SFlorian Westphal #define _GNU_SOURCE
4ce997912SFlorian Westphal 
5ce997912SFlorian Westphal #include <assert.h>
6ce997912SFlorian Westphal #include <errno.h>
7edb596e8SFlorian Westphal #include <fcntl.h>
8ce997912SFlorian Westphal #include <limits.h>
9ce997912SFlorian Westphal #include <string.h>
10ce997912SFlorian Westphal #include <stdarg.h>
11ce997912SFlorian Westphal #include <stdbool.h>
12ce997912SFlorian Westphal #include <stdint.h>
13ce997912SFlorian Westphal #include <inttypes.h>
14ce997912SFlorian Westphal #include <stdio.h>
15ce997912SFlorian Westphal #include <stdlib.h>
16ce997912SFlorian Westphal #include <strings.h>
17edb596e8SFlorian Westphal #include <time.h>
18ce997912SFlorian Westphal #include <unistd.h>
19ce997912SFlorian Westphal 
20ce997912SFlorian Westphal #include <sys/socket.h>
21ce997912SFlorian Westphal #include <sys/types.h>
22ce997912SFlorian Westphal #include <sys/wait.h>
23ce997912SFlorian Westphal 
24ce997912SFlorian Westphal #include <netdb.h>
25ce997912SFlorian Westphal #include <netinet/in.h>
26ce997912SFlorian Westphal 
27ce997912SFlorian Westphal #include <linux/tcp.h>
28ce997912SFlorian Westphal 
29ce997912SFlorian Westphal static int pf = AF_INET;
30ce997912SFlorian Westphal 
31ce997912SFlorian Westphal #ifndef IPPROTO_MPTCP
32ce997912SFlorian Westphal #define IPPROTO_MPTCP 262
33ce997912SFlorian Westphal #endif
34ce997912SFlorian Westphal #ifndef SOL_MPTCP
35ce997912SFlorian Westphal #define SOL_MPTCP 284
36ce997912SFlorian Westphal #endif
37ce997912SFlorian Westphal 
38ce997912SFlorian Westphal #ifndef MPTCP_INFO
39ce997912SFlorian Westphal struct mptcp_info {
40ce997912SFlorian Westphal 	__u8	mptcpi_subflows;
41ce997912SFlorian Westphal 	__u8	mptcpi_add_addr_signal;
42ce997912SFlorian Westphal 	__u8	mptcpi_add_addr_accepted;
43ce997912SFlorian Westphal 	__u8	mptcpi_subflows_max;
44ce997912SFlorian Westphal 	__u8	mptcpi_add_addr_signal_max;
45ce997912SFlorian Westphal 	__u8	mptcpi_add_addr_accepted_max;
46ce997912SFlorian Westphal 	__u32	mptcpi_flags;
47ce997912SFlorian Westphal 	__u32	mptcpi_token;
48ce997912SFlorian Westphal 	__u64	mptcpi_write_seq;
49ce997912SFlorian Westphal 	__u64	mptcpi_snd_una;
50ce997912SFlorian Westphal 	__u64	mptcpi_rcv_nxt;
51ce997912SFlorian Westphal 	__u8	mptcpi_local_addr_used;
52ce997912SFlorian Westphal 	__u8	mptcpi_local_addr_max;
53ce997912SFlorian Westphal 	__u8	mptcpi_csum_enabled;
54ce997912SFlorian Westphal 	__u32	mptcpi_retransmits;
55ce997912SFlorian Westphal 	__u64	mptcpi_bytes_retrans;
56ce997912SFlorian Westphal 	__u64	mptcpi_bytes_sent;
57ce997912SFlorian Westphal 	__u64	mptcpi_bytes_received;
58ce997912SFlorian Westphal 	__u64	mptcpi_bytes_acked;
59ce997912SFlorian Westphal };
60ce997912SFlorian Westphal 
61ce997912SFlorian Westphal struct mptcp_subflow_data {
62ce997912SFlorian Westphal 	__u32		size_subflow_data;		/* size of this structure in userspace */
63ce997912SFlorian Westphal 	__u32		num_subflows;			/* must be 0, set by kernel */
64ce997912SFlorian Westphal 	__u32		size_kernel;			/* must be 0, set by kernel */
65ce997912SFlorian Westphal 	__u32		size_user;			/* size of one element in data[] */
66ce997912SFlorian Westphal } __attribute__((aligned(8)));
67ce997912SFlorian Westphal 
68ce997912SFlorian Westphal struct mptcp_subflow_addrs {
69ce997912SFlorian Westphal 	union {
70ce997912SFlorian Westphal 		__kernel_sa_family_t sa_family;
71ce997912SFlorian Westphal 		struct sockaddr sa_local;
72ce997912SFlorian Westphal 		struct sockaddr_in sin_local;
73ce997912SFlorian Westphal 		struct sockaddr_in6 sin6_local;
74ce997912SFlorian Westphal 		struct __kernel_sockaddr_storage ss_local;
75ce997912SFlorian Westphal 	};
76ce997912SFlorian Westphal 	union {
77ce997912SFlorian Westphal 		struct sockaddr sa_remote;
78ce997912SFlorian Westphal 		struct sockaddr_in sin_remote;
79ce997912SFlorian Westphal 		struct sockaddr_in6 sin6_remote;
80ce997912SFlorian Westphal 		struct __kernel_sockaddr_storage ss_remote;
81ce997912SFlorian Westphal 	};
82ce997912SFlorian Westphal };
83ce997912SFlorian Westphal 
84ce997912SFlorian Westphal #define MPTCP_INFO		1
85ce997912SFlorian Westphal #define MPTCP_TCPINFO		2
86ce997912SFlorian Westphal #define MPTCP_SUBFLOW_ADDRS	3
87ce997912SFlorian Westphal #endif
88ce997912SFlorian Westphal 
89ce997912SFlorian Westphal #ifndef MPTCP_FULL_INFO
90*8dee6ca2SMatthieu Baerts struct mptcp_subflow_info {
91*8dee6ca2SMatthieu Baerts 	__u32				id;
92*8dee6ca2SMatthieu Baerts 	struct mptcp_subflow_addrs	addrs;
93*8dee6ca2SMatthieu Baerts };
94ce997912SFlorian Westphal 
95ce997912SFlorian Westphal struct mptcp_full_info {
96ce997912SFlorian Westphal 	__u32		size_tcpinfo_kernel;	/* must be 0, set by kernel */
97ce997912SFlorian Westphal 	__u32		size_tcpinfo_user;
98ce997912SFlorian Westphal 	__u32		size_sfinfo_kernel;	/* must be 0, set by kernel */
99ce997912SFlorian Westphal 	__u32		size_sfinfo_user;
100ce997912SFlorian Westphal 	__u32		num_subflows;		/* must be 0, set by kernel (real subflow count) */
101ce997912SFlorian Westphal 	__u32		size_arrays_user;	/* max subflows that userspace is interested in;
102ce997912SFlorian Westphal 						 * the buffers at subflow_info/tcp_info
103ce997912SFlorian Westphal 						 * are respectively at least:
104ce997912SFlorian Westphal 						 *  size_arrays * size_sfinfo_user
105ce997912SFlorian Westphal 						 *  size_arrays * size_tcpinfo_user
106ce997912SFlorian Westphal 						 * bytes wide
107ce997912SFlorian Westphal 						 */
108ce997912SFlorian Westphal 	__aligned_u64		subflow_info;
109ce997912SFlorian Westphal 	__aligned_u64		tcp_info;
110ce997912SFlorian Westphal 	struct mptcp_info	mptcp_info;
111ce997912SFlorian Westphal };
112ce997912SFlorian Westphal 
113ce997912SFlorian Westphal #define MPTCP_FULL_INFO		4
114ce997912SFlorian Westphal #endif
115ce997912SFlorian Westphal 
116ce997912SFlorian Westphal struct so_state {
117ce997912SFlorian Westphal 	struct mptcp_info mi;
118ce997912SFlorian Westphal 	struct mptcp_info last_sample;
119ce997912SFlorian Westphal 	struct tcp_info tcp_info;
120ce997912SFlorian Westphal 	struct mptcp_subflow_addrs addrs;
121ce997912SFlorian Westphal 	uint64_t mptcpi_rcv_delta;
122ce997912SFlorian Westphal 	uint64_t tcpi_rcv_delta;
123ce997912SFlorian Westphal 	bool pkt_stats_avail;
124ce997912SFlorian Westphal };
125ce997912SFlorian Westphal 
126ce997912SFlorian Westphal #ifndef MIN
127ce997912SFlorian Westphal #define MIN(a, b) ((a) < (b) ? (a) : (b))
128ce997912SFlorian Westphal #endif
129ce997912SFlorian Westphal 
die_perror(const char * msg)130ce997912SFlorian Westphal static void die_perror(const char *msg)
131ce997912SFlorian Westphal {
132ce997912SFlorian Westphal 	perror(msg);
133ce997912SFlorian Westphal 	exit(1);
134ce997912SFlorian Westphal }
135ce997912SFlorian Westphal 
die_usage(int r)136ce997912SFlorian Westphal static void die_usage(int r)
137ce997912SFlorian Westphal {
138ce997912SFlorian Westphal 	fprintf(stderr, "Usage: mptcp_sockopt [-6]\n");
139ce997912SFlorian Westphal 	exit(r);
140ce997912SFlorian Westphal }
141ce997912SFlorian Westphal 
xerror(const char * fmt,...)142ce997912SFlorian Westphal static void xerror(const char *fmt, ...)
143fd37c2ecSMat Martineau {
144ce997912SFlorian Westphal 	va_list ap;
145ce997912SFlorian Westphal 
146ce997912SFlorian Westphal 	va_start(ap, fmt);
147ce997912SFlorian Westphal 	vfprintf(stderr, fmt, ap);
148ce997912SFlorian Westphal 	va_end(ap);
149ce997912SFlorian Westphal 	fputc('\n', stderr);
150ce997912SFlorian Westphal 	exit(1);
151ce997912SFlorian Westphal }
152ce997912SFlorian Westphal 
getxinfo_strerr(int err)153ce997912SFlorian Westphal static const char *getxinfo_strerr(int err)
154ce997912SFlorian Westphal {
155ce997912SFlorian Westphal 	if (err == EAI_SYSTEM)
156ce997912SFlorian Westphal 		return strerror(errno);
157ce997912SFlorian Westphal 
158ce997912SFlorian Westphal 	return gai_strerror(err);
159ce997912SFlorian Westphal }
160ce997912SFlorian Westphal 
xgetaddrinfo(const char * node,const char * service,const struct addrinfo * hints,struct addrinfo ** res)161ce997912SFlorian Westphal static void xgetaddrinfo(const char *node, const char *service,
162ce997912SFlorian Westphal 			 const struct addrinfo *hints,
163ce997912SFlorian Westphal 			 struct addrinfo **res)
164ce997912SFlorian Westphal {
165ce997912SFlorian Westphal 	int err = getaddrinfo(node, service, hints, res);
166ce997912SFlorian Westphal 
167ce997912SFlorian Westphal 	if (err) {
168ce997912SFlorian Westphal 		const char *errstr = getxinfo_strerr(err);
169ce997912SFlorian Westphal 
170ce997912SFlorian Westphal 		fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
171ce997912SFlorian Westphal 			node ? node : "", service ? service : "", errstr);
172ce997912SFlorian Westphal 		exit(1);
173ce997912SFlorian Westphal 	}
174ce997912SFlorian Westphal }
175ce997912SFlorian Westphal 
sock_listen_mptcp(const char * const listenaddr,const char * const port)176ce997912SFlorian Westphal static int sock_listen_mptcp(const char * const listenaddr,
177ce997912SFlorian Westphal 			     const char * const port)
178ce997912SFlorian Westphal {
179ce997912SFlorian Westphal 	int sock = -1;
180ce997912SFlorian Westphal 	struct addrinfo hints = {
181ce997912SFlorian Westphal 		.ai_protocol = IPPROTO_TCP,
182ce997912SFlorian Westphal 		.ai_socktype = SOCK_STREAM,
183ce997912SFlorian Westphal 		.ai_flags = AI_PASSIVE | AI_NUMERICHOST
184ce997912SFlorian Westphal 	};
185ce997912SFlorian Westphal 
186ce997912SFlorian Westphal 	hints.ai_family = pf;
187ce997912SFlorian Westphal 
188ce997912SFlorian Westphal 	struct addrinfo *a, *addr;
189ce997912SFlorian Westphal 	int one = 1;
190ce997912SFlorian Westphal 
191ce997912SFlorian Westphal 	xgetaddrinfo(listenaddr, port, &hints, &addr);
192ce997912SFlorian Westphal 	hints.ai_family = pf;
193ce997912SFlorian Westphal 
194ce997912SFlorian Westphal 	for (a = addr; a; a = a->ai_next) {
195ce997912SFlorian Westphal 		sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
196ce997912SFlorian Westphal 		if (sock < 0)
197ce997912SFlorian Westphal 			continue;
198ce997912SFlorian Westphal 
199ce997912SFlorian Westphal 		if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
200ce997912SFlorian Westphal 				     sizeof(one)))
201ce997912SFlorian Westphal 			perror("setsockopt");
202ce997912SFlorian Westphal 
203ce997912SFlorian Westphal 		if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
204ce997912SFlorian Westphal 			break; /* success */
205ce997912SFlorian Westphal 
206ce997912SFlorian Westphal 		perror("bind");
207ce997912SFlorian Westphal 		close(sock);
208ce997912SFlorian Westphal 		sock = -1;
209ce997912SFlorian Westphal 	}
210ce997912SFlorian Westphal 
211ce997912SFlorian Westphal 	freeaddrinfo(addr);
212ce997912SFlorian Westphal 
213ce997912SFlorian Westphal 	if (sock < 0)
214ce997912SFlorian Westphal 		xerror("could not create listen socket");
215ce997912SFlorian Westphal 
216ce997912SFlorian Westphal 	if (listen(sock, 20))
217ce997912SFlorian Westphal 		die_perror("listen");
218ce997912SFlorian Westphal 
219ce997912SFlorian Westphal 	return sock;
220ce997912SFlorian Westphal }
221ce997912SFlorian Westphal 
sock_connect_mptcp(const char * const remoteaddr,const char * const port,int proto)222ce997912SFlorian Westphal static int sock_connect_mptcp(const char * const remoteaddr,
223ce997912SFlorian Westphal 			      const char * const port, int proto)
224ce997912SFlorian Westphal {
225ce997912SFlorian Westphal 	struct addrinfo hints = {
226ce997912SFlorian Westphal 		.ai_protocol = IPPROTO_TCP,
227ce997912SFlorian Westphal 		.ai_socktype = SOCK_STREAM,
228ce997912SFlorian Westphal 	};
229ce997912SFlorian Westphal 	struct addrinfo *a, *addr;
230ce997912SFlorian Westphal 	int sock = -1;
231ce997912SFlorian Westphal 
232ce997912SFlorian Westphal 	hints.ai_family = pf;
233ce997912SFlorian Westphal 
234ce997912SFlorian Westphal 	xgetaddrinfo(remoteaddr, port, &hints, &addr);
235ce997912SFlorian Westphal 	for (a = addr; a; a = a->ai_next) {
236ce997912SFlorian Westphal 		sock = socket(a->ai_family, a->ai_socktype, proto);
237ce997912SFlorian Westphal 		if (sock < 0)
238ce997912SFlorian Westphal 			continue;
239ce997912SFlorian Westphal 
240ce997912SFlorian Westphal 		if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
241ce997912SFlorian Westphal 			break; /* success */
242ce997912SFlorian Westphal 
243ce997912SFlorian Westphal 		die_perror("connect");
244ce997912SFlorian Westphal 	}
245ce997912SFlorian Westphal 
246ce997912SFlorian Westphal 	if (sock < 0)
247ce997912SFlorian Westphal 		xerror("could not create connect socket");
248ce997912SFlorian Westphal 
249ce997912SFlorian Westphal 	freeaddrinfo(addr);
250ce997912SFlorian Westphal 	return sock;
251ce997912SFlorian Westphal }
252ce997912SFlorian Westphal 
parse_opts(int argc,char ** argv)253ce997912SFlorian Westphal static void parse_opts(int argc, char **argv)
254ce997912SFlorian Westphal {
255ce997912SFlorian Westphal 	int c;
256ce997912SFlorian Westphal 
257ce997912SFlorian Westphal 	while ((c = getopt(argc, argv, "h6")) != -1) {
258ce997912SFlorian Westphal 		switch (c) {
259ce997912SFlorian Westphal 		case 'h':
260ce997912SFlorian Westphal 			die_usage(0);
261ce997912SFlorian Westphal 			break;
262ce997912SFlorian Westphal 		case '6':
263ce997912SFlorian Westphal 			pf = AF_INET6;
264ce997912SFlorian Westphal 			break;
265ce997912SFlorian Westphal 		default:
266ce997912SFlorian Westphal 			die_usage(1);
267ce997912SFlorian Westphal 			break;
268ce997912SFlorian Westphal 		}
269ce997912SFlorian Westphal 	}
270ce997912SFlorian Westphal }
271ce997912SFlorian Westphal 
do_getsockopt_bogus_sf_data(int fd,int optname)272ce997912SFlorian Westphal static void do_getsockopt_bogus_sf_data(int fd, int optname)
273ce997912SFlorian Westphal {
274ce997912SFlorian Westphal 	struct mptcp_subflow_data good_data;
275ce997912SFlorian Westphal 	struct bogus_data {
276ce997912SFlorian Westphal 		struct mptcp_subflow_data d;
277ce997912SFlorian Westphal 		char buf[2];
278ce997912SFlorian Westphal 	} bd;
279ce997912SFlorian Westphal 	socklen_t olen, _olen;
280ce997912SFlorian Westphal 	int ret;
281ce997912SFlorian Westphal 
282ce997912SFlorian Westphal 	memset(&bd, 0, sizeof(bd));
283ce997912SFlorian Westphal 	memset(&good_data, 0, sizeof(good_data));
284ce997912SFlorian Westphal 
285ce997912SFlorian Westphal 	olen = sizeof(good_data);
286ce997912SFlorian Westphal 	good_data.size_subflow_data = olen;
287ce997912SFlorian Westphal 
288ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
289ce997912SFlorian Westphal 	assert(ret < 0); /* 0 size_subflow_data */
290ce997912SFlorian Westphal 	assert(olen == sizeof(good_data));
291ce997912SFlorian Westphal 
292ce997912SFlorian Westphal 	bd.d = good_data;
293ce997912SFlorian Westphal 
294ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
295ce997912SFlorian Westphal 	assert(ret == 0);
296ce997912SFlorian Westphal 	assert(olen == sizeof(good_data));
297ce997912SFlorian Westphal 	assert(bd.d.num_subflows == 1);
298ce997912SFlorian Westphal 	assert(bd.d.size_kernel > 0);
299ce997912SFlorian Westphal 	assert(bd.d.size_user == 0);
300ce997912SFlorian Westphal 
301ce997912SFlorian Westphal 	bd.d = good_data;
302ce997912SFlorian Westphal 	_olen = rand() % olen;
303ce997912SFlorian Westphal 	olen = _olen;
304ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
305ce997912SFlorian Westphal 	assert(ret < 0);	/* bogus olen */
306ce997912SFlorian Westphal 	assert(olen == _olen);	/* must be unchanged */
307ce997912SFlorian Westphal 
308ce997912SFlorian Westphal 	bd.d = good_data;
309ce997912SFlorian Westphal 	olen = sizeof(good_data);
310ce997912SFlorian Westphal 	bd.d.size_kernel = 1;
311ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
312ce997912SFlorian Westphal 	assert(ret < 0); /* size_kernel not 0 */
313ce997912SFlorian Westphal 
314ce997912SFlorian Westphal 	bd.d = good_data;
315ce997912SFlorian Westphal 	olen = sizeof(good_data);
316ce997912SFlorian Westphal 	bd.d.num_subflows = 1;
317ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
318ce997912SFlorian Westphal 	assert(ret < 0); /* num_subflows not 0 */
319ce997912SFlorian Westphal 
320ce997912SFlorian Westphal 	/* forward compat check: larger struct mptcp_subflow_data on 'old' kernel */
321ce997912SFlorian Westphal 	bd.d = good_data;
322ce997912SFlorian Westphal 	olen = sizeof(bd);
323ce997912SFlorian Westphal 	bd.d.size_subflow_data = sizeof(bd);
324ce997912SFlorian Westphal 
325ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
326ce997912SFlorian Westphal 	assert(ret == 0);
327ce997912SFlorian Westphal 
328ce997912SFlorian Westphal 	/* olen must be truncated to real data size filled by kernel: */
329ce997912SFlorian Westphal 	assert(olen == sizeof(good_data));
330ce997912SFlorian Westphal 
331ce997912SFlorian Westphal 	assert(bd.d.size_subflow_data == sizeof(bd));
332ce997912SFlorian Westphal 
333ce997912SFlorian Westphal 	bd.d = good_data;
334ce997912SFlorian Westphal 	bd.d.size_subflow_data += 1;
335ce997912SFlorian Westphal 	bd.d.size_user = 1;
336ce997912SFlorian Westphal 	olen = bd.d.size_subflow_data + 1;
337ce997912SFlorian Westphal 	_olen = olen;
338ce997912SFlorian Westphal 
339ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &_olen);
340ce997912SFlorian Westphal 	assert(ret == 0);
341ce997912SFlorian Westphal 
342ce997912SFlorian Westphal 	/* no truncation, kernel should have filled 1 byte of optname payload in buf[1]: */
343ce997912SFlorian Westphal 	assert(olen == _olen);
344ce997912SFlorian Westphal 
345ce997912SFlorian Westphal 	assert(bd.d.size_subflow_data == sizeof(good_data) + 1);
346ce997912SFlorian Westphal 	assert(bd.buf[0] == 0);
347ce997912SFlorian Westphal }
348ce997912SFlorian Westphal 
do_getsockopt_mptcp_info(struct so_state * s,int fd,size_t w)349ce997912SFlorian Westphal static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
350ce997912SFlorian Westphal {
351ce997912SFlorian Westphal 	struct mptcp_info i;
352ce997912SFlorian Westphal 	socklen_t olen;
353ce997912SFlorian Westphal 	int ret;
354ce997912SFlorian Westphal 
355ce997912SFlorian Westphal 	olen = sizeof(i);
356*8dee6ca2SMatthieu Baerts 	ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen);
357*8dee6ca2SMatthieu Baerts 
358*8dee6ca2SMatthieu Baerts 	if (ret < 0)
359ce997912SFlorian Westphal 		die_perror("getsockopt MPTCP_INFO");
360ce997912SFlorian Westphal 
361ce997912SFlorian Westphal 	s->pkt_stats_avail = olen >= sizeof(i);
362ce997912SFlorian Westphal 
363*8dee6ca2SMatthieu Baerts 	s->last_sample = i;
364ce997912SFlorian Westphal 	if (s->mi.mptcpi_write_seq == 0)
365ce997912SFlorian Westphal 		s->mi = i;
366ce997912SFlorian Westphal 
367ce997912SFlorian Westphal 	assert(s->mi.mptcpi_write_seq + w == i.mptcpi_write_seq);
368ce997912SFlorian Westphal 
369ce997912SFlorian Westphal 	s->mptcpi_rcv_delta = i.mptcpi_rcv_nxt - s->mi.mptcpi_rcv_nxt;
370ce997912SFlorian Westphal }
371ce997912SFlorian Westphal 
do_getsockopt_tcp_info(struct so_state * s,int fd,size_t r,size_t w)372ce997912SFlorian Westphal static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t w)
373ce997912SFlorian Westphal {
374ce997912SFlorian Westphal 	struct my_tcp_info {
375ce997912SFlorian Westphal 		struct mptcp_subflow_data d;
376ce997912SFlorian Westphal 		struct tcp_info ti[2];
377ce997912SFlorian Westphal 	} ti;
378ce997912SFlorian Westphal 	int ret, tries = 5;
379ce997912SFlorian Westphal 	socklen_t olen;
380ce997912SFlorian Westphal 
381ce997912SFlorian Westphal 	do {
382ce997912SFlorian Westphal 		memset(&ti, 0, sizeof(ti));
383ce997912SFlorian Westphal 
384ce997912SFlorian Westphal 		ti.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
385ce997912SFlorian Westphal 		ti.d.size_user = sizeof(struct tcp_info);
386ce997912SFlorian Westphal 		olen = sizeof(ti);
387ce997912SFlorian Westphal 
388ce997912SFlorian Westphal 		ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen);
389ce997912SFlorian Westphal 		if (ret < 0)
390ce997912SFlorian Westphal 			xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
391ce997912SFlorian Westphal 
392ce997912SFlorian Westphal 		assert(olen <= sizeof(ti));
393ce997912SFlorian Westphal 		assert(ti.d.size_kernel > 0);
394ce997912SFlorian Westphal 		assert(ti.d.size_user ==
395ce997912SFlorian Westphal 		       MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
396ce997912SFlorian Westphal 		assert(ti.d.num_subflows == 1);
397ce997912SFlorian Westphal 
398ce997912SFlorian Westphal 		assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
399ce997912SFlorian Westphal 		olen -= sizeof(struct mptcp_subflow_data);
400ce997912SFlorian Westphal 		assert(olen == ti.d.size_user);
401ce997912SFlorian Westphal 
402ce997912SFlorian Westphal 		s->tcp_info = ti.ti[0];
403ce997912SFlorian Westphal 
404ce997912SFlorian Westphal 		if (ti.ti[0].tcpi_bytes_sent == w &&
405ce997912SFlorian Westphal 		    ti.ti[0].tcpi_bytes_received == r)
406ce997912SFlorian Westphal 			goto done;
407ce997912SFlorian Westphal 
408ce997912SFlorian Westphal 		if (r == 0 && ti.ti[0].tcpi_bytes_sent == w &&
409*8dee6ca2SMatthieu Baerts 		    ti.ti[0].tcpi_bytes_received) {
410*8dee6ca2SMatthieu Baerts 			s->tcpi_rcv_delta = ti.ti[0].tcpi_bytes_received;
411*8dee6ca2SMatthieu Baerts 			goto done;
412ce997912SFlorian Westphal 		}
413ce997912SFlorian Westphal 
414ce997912SFlorian Westphal 		/* wait and repeat, might be that tx is still ongoing */
415ce997912SFlorian Westphal 		sleep(1);
416*8dee6ca2SMatthieu Baerts 	} while (tries-- > 0);
417ce997912SFlorian Westphal 
418ce997912SFlorian Westphal 	xerror("tcpi_bytes_sent %" PRIu64 ", want %zu. tcpi_bytes_received %" PRIu64 ", want %zu",
419ce997912SFlorian Westphal 		ti.ti[0].tcpi_bytes_sent, w, ti.ti[0].tcpi_bytes_received, r);
420ce997912SFlorian Westphal 
421ce997912SFlorian Westphal done:
422ce997912SFlorian Westphal 	do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
423ce997912SFlorian Westphal }
424ce997912SFlorian Westphal 
do_getsockopt_subflow_addrs(struct so_state * s,int fd)425ce997912SFlorian Westphal static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
426ce997912SFlorian Westphal {
427ce997912SFlorian Westphal 	struct sockaddr_storage remote, local;
428ce997912SFlorian Westphal 	socklen_t olen, rlen, llen;
429ce997912SFlorian Westphal 	int ret;
430ce997912SFlorian Westphal 	struct my_addrs {
431ce997912SFlorian Westphal 		struct mptcp_subflow_data d;
432ce997912SFlorian Westphal 		struct mptcp_subflow_addrs addr[2];
433ce997912SFlorian Westphal 	} addrs;
434ce997912SFlorian Westphal 
435ce997912SFlorian Westphal 	memset(&addrs, 0, sizeof(addrs));
436ce997912SFlorian Westphal 	memset(&local, 0, sizeof(local));
437ce997912SFlorian Westphal 	memset(&remote, 0, sizeof(remote));
438ce997912SFlorian Westphal 
439ce997912SFlorian Westphal 	addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
440ce997912SFlorian Westphal 	addrs.d.size_user = sizeof(struct mptcp_subflow_addrs);
441ce997912SFlorian Westphal 	olen = sizeof(addrs);
442ce997912SFlorian Westphal 
443ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
444ce997912SFlorian Westphal 	if (ret < 0)
445ce997912SFlorian Westphal 		die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
446ce997912SFlorian Westphal 
447ce997912SFlorian Westphal 	assert(olen <= sizeof(addrs));
448ce997912SFlorian Westphal 	assert(addrs.d.size_kernel > 0);
449ce997912SFlorian Westphal 	assert(addrs.d.size_user ==
450ce997912SFlorian Westphal 	       MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
451ce997912SFlorian Westphal 	assert(addrs.d.num_subflows == 1);
452ce997912SFlorian Westphal 
453ce997912SFlorian Westphal 	assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
454ce997912SFlorian Westphal 	olen -= sizeof(struct mptcp_subflow_data);
455ce997912SFlorian Westphal 	assert(olen == addrs.d.size_user);
456ce997912SFlorian Westphal 
457ce997912SFlorian Westphal 	llen = sizeof(local);
458ce997912SFlorian Westphal 	ret = getsockname(fd, (struct sockaddr *)&local, &llen);
459ce997912SFlorian Westphal 	if (ret < 0)
460ce997912SFlorian Westphal 		die_perror("getsockname");
461ce997912SFlorian Westphal 	rlen = sizeof(remote);
462ce997912SFlorian Westphal 	ret = getpeername(fd, (struct sockaddr *)&remote, &rlen);
463ce997912SFlorian Westphal 	if (ret < 0)
464ce997912SFlorian Westphal 		die_perror("getpeername");
465ce997912SFlorian Westphal 
466ce997912SFlorian Westphal 	assert(rlen > 0);
467ce997912SFlorian Westphal 	assert(rlen == llen);
468ce997912SFlorian Westphal 
469ce997912SFlorian Westphal 	assert(remote.ss_family == local.ss_family);
470ce997912SFlorian Westphal 
471ce997912SFlorian Westphal 	assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
472ce997912SFlorian Westphal 	assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
473ce997912SFlorian Westphal 	s->addrs = addrs.addr[0];
474ce997912SFlorian Westphal 
475ce997912SFlorian Westphal 	memset(&addrs, 0, sizeof(addrs));
476ce997912SFlorian Westphal 
477ce997912SFlorian Westphal 	addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
478ce997912SFlorian Westphal 	addrs.d.size_user = sizeof(sa_family_t);
479ce997912SFlorian Westphal 	olen = sizeof(addrs.d) + sizeof(sa_family_t);
480ce997912SFlorian Westphal 
481ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
482ce997912SFlorian Westphal 	assert(ret == 0);
483ce997912SFlorian Westphal 	assert(olen == sizeof(addrs.d) + sizeof(sa_family_t));
484ce997912SFlorian Westphal 
485ce997912SFlorian Westphal 	assert(addrs.addr[0].sa_family == pf);
486ce997912SFlorian Westphal 	assert(addrs.addr[0].sa_family == local.ss_family);
487ce997912SFlorian Westphal 
488ce997912SFlorian Westphal 	assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) != 0);
489ce997912SFlorian Westphal 	assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) != 0);
490ce997912SFlorian Westphal 
491ce997912SFlorian Westphal 	do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
492ce997912SFlorian Westphal }
493ce997912SFlorian Westphal 
do_getsockopt_mptcp_full_info(struct so_state * s,int fd)494ce997912SFlorian Westphal static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
495ce997912SFlorian Westphal {
496ce997912SFlorian Westphal 	size_t data_size = sizeof(struct mptcp_full_info);
497ce997912SFlorian Westphal 	struct mptcp_subflow_info sfinfo[2];
498ce997912SFlorian Westphal 	struct tcp_info tcp_info[2];
499ce997912SFlorian Westphal 	struct mptcp_full_info mfi;
500ce997912SFlorian Westphal 	socklen_t olen;
501ce997912SFlorian Westphal 	int ret;
502ce997912SFlorian Westphal 
503ce997912SFlorian Westphal 	memset(&mfi, 0, data_size);
504ce997912SFlorian Westphal 	memset(tcp_info, 0, sizeof(tcp_info));
505ce997912SFlorian Westphal 	memset(sfinfo, 0, sizeof(sfinfo));
506ce997912SFlorian Westphal 
507ce997912SFlorian Westphal 	mfi.size_tcpinfo_user = sizeof(struct tcp_info);
508ce997912SFlorian Westphal 	mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info);
509ce997912SFlorian Westphal 	mfi.size_arrays_user = 2;
510ce997912SFlorian Westphal 	mfi.subflow_info = (unsigned long)&sfinfo[0];
511ce997912SFlorian Westphal 	mfi.tcp_info = (unsigned long)&tcp_info[0];
512ce997912SFlorian Westphal 	olen = data_size;
513ce997912SFlorian Westphal 
514ce997912SFlorian Westphal 	ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
515ce997912SFlorian Westphal 	if (ret < 0) {
516ce997912SFlorian Westphal 		if (errno == EOPNOTSUPP) {
517ce997912SFlorian Westphal 			perror("MPTCP_FULL_INFO test skipped");
518ce997912SFlorian Westphal 			return;
519ce997912SFlorian Westphal 		}
520ce997912SFlorian Westphal 		xerror("getsockopt MPTCP_FULL_INFO");
521ce997912SFlorian Westphal 	}
522ce997912SFlorian Westphal 
523ce997912SFlorian Westphal 	assert(olen <= data_size);
524ce997912SFlorian Westphal 	assert(mfi.size_tcpinfo_kernel > 0);
525ce997912SFlorian Westphal 	assert(mfi.size_tcpinfo_user ==
526ce997912SFlorian Westphal 	       MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info)));
527ce997912SFlorian Westphal 	assert(mfi.size_sfinfo_kernel > 0);
528ce997912SFlorian Westphal 	assert(mfi.size_sfinfo_user ==
529ce997912SFlorian Westphal 	       MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info)));
530ce997912SFlorian Westphal 	assert(mfi.num_subflows == 1);
531ce997912SFlorian Westphal 
532ce997912SFlorian Westphal 	/* Tolerate future extension to mptcp_info struct and running newer
533ce997912SFlorian Westphal 	 * test on top of older kernel.
534ce997912SFlorian Westphal 	 * Anyway any kernel supporting MPTCP_FULL_INFO must at least include
535ce997912SFlorian Westphal 	 * the following in mptcp_info.
536ce997912SFlorian Westphal 	 */
537ce997912SFlorian Westphal 	assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info));
538ce997912SFlorian Westphal 	assert(mfi.mptcp_info.mptcpi_subflows == 0);
539ce997912SFlorian Westphal 	assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent);
540ce997912SFlorian Westphal 	assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received);
541ce997912SFlorian Westphal 
542ce997912SFlorian Westphal 	assert(sfinfo[0].id == 1);
543ce997912SFlorian Westphal 	assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent);
544ce997912SFlorian Westphal 	assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received);
545ce997912SFlorian Westphal 	assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs)));
546ce997912SFlorian Westphal }
547ce997912SFlorian Westphal 
do_getsockopts(struct so_state * s,int fd,size_t r,size_t w)548ce997912SFlorian Westphal static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
549ce997912SFlorian Westphal {
550ce997912SFlorian Westphal 	do_getsockopt_mptcp_info(s, fd, w);
551ce997912SFlorian Westphal 
552ce997912SFlorian Westphal 	do_getsockopt_tcp_info(s, fd, r, w);
553ce997912SFlorian Westphal 
554ce997912SFlorian Westphal 	do_getsockopt_subflow_addrs(s, fd);
555ce997912SFlorian Westphal 
556ce997912SFlorian Westphal 	if (r)
557ce997912SFlorian Westphal 		do_getsockopt_mptcp_full_info(s, fd);
558ce997912SFlorian Westphal }
559ce997912SFlorian Westphal 
connect_one_server(int fd,int pipefd)560ce997912SFlorian Westphal static void connect_one_server(int fd, int pipefd)
561ce997912SFlorian Westphal {
562ce997912SFlorian Westphal 	char buf[4096], buf2[4096];
563ce997912SFlorian Westphal 	size_t len, i, total;
564ce997912SFlorian Westphal 	struct so_state s;
565ce997912SFlorian Westphal 	bool eof = false;
566ce997912SFlorian Westphal 	ssize_t ret;
567ce997912SFlorian Westphal 
568ce997912SFlorian Westphal 	memset(&s, 0, sizeof(s));
569ce997912SFlorian Westphal 
570ce997912SFlorian Westphal 	len = rand() % (sizeof(buf) - 1);
571ce997912SFlorian Westphal 
572ce997912SFlorian Westphal 	if (len < 128)
573ce997912SFlorian Westphal 		len = 128;
574ce997912SFlorian Westphal 
575ce997912SFlorian Westphal 	for (i = 0; i < len ; i++) {
576ce997912SFlorian Westphal 		buf[i] = rand() % 26;
577ce997912SFlorian Westphal 		buf[i] += 'A';
578ce997912SFlorian Westphal 	}
579ce997912SFlorian Westphal 
580ce997912SFlorian Westphal 	buf[i] = '\n';
581ce997912SFlorian Westphal 
582ce997912SFlorian Westphal 	do_getsockopts(&s, fd, 0, 0);
583ce997912SFlorian Westphal 
584ce997912SFlorian Westphal 	/* un-block server */
585ce997912SFlorian Westphal 	ret = read(pipefd, buf2, 4);
586ce997912SFlorian Westphal 	assert(ret == 4);
587ce997912SFlorian Westphal 	close(pipefd);
588ce997912SFlorian Westphal 
589ce997912SFlorian Westphal 	assert(strncmp(buf2, "xmit", 4) == 0);
590ce997912SFlorian Westphal 
591ce997912SFlorian Westphal 	ret = write(fd, buf, len);
592ce997912SFlorian Westphal 	if (ret < 0)
593ce997912SFlorian Westphal 		die_perror("write");
594ce997912SFlorian Westphal 
595ce997912SFlorian Westphal 	if (ret != (ssize_t)len)
596ce997912SFlorian Westphal 		xerror("short write");
597ce997912SFlorian Westphal 
598ce997912SFlorian Westphal 	total = 0;
599ce997912SFlorian Westphal 	do {
600ce997912SFlorian Westphal 		ret = read(fd, buf2 + total, sizeof(buf2) - total);
601ce997912SFlorian Westphal 		if (ret < 0)
602ce997912SFlorian Westphal 			die_perror("read");
603ce997912SFlorian Westphal 		if (ret == 0) {
604ce997912SFlorian Westphal 			eof = true;
605edb596e8SFlorian Westphal 			break;
606edb596e8SFlorian Westphal 		}
607edb596e8SFlorian Westphal 
608edb596e8SFlorian Westphal 		total += ret;
609edb596e8SFlorian Westphal 	} while (total < len);
610edb596e8SFlorian Westphal 
611edb596e8SFlorian Westphal 	if (total != len)
612edb596e8SFlorian Westphal 		xerror("total %lu, len %lu eof %d\n", total, len, eof);
613edb596e8SFlorian Westphal 
614edb596e8SFlorian Westphal 	if (memcmp(buf, buf2, len))
615edb596e8SFlorian Westphal 		xerror("data corruption");
616edb596e8SFlorian Westphal 
617edb596e8SFlorian Westphal 	if (s.tcpi_rcv_delta)
618edb596e8SFlorian Westphal 		assert(s.tcpi_rcv_delta <= total);
619edb596e8SFlorian Westphal 
620edb596e8SFlorian Westphal 	do_getsockopts(&s, fd, ret, ret);
621edb596e8SFlorian Westphal 
622edb596e8SFlorian Westphal 	if (eof)
623edb596e8SFlorian Westphal 		total += 1; /* sequence advances due to FIN */
624edb596e8SFlorian Westphal 
625edb596e8SFlorian Westphal 	assert(s.mptcpi_rcv_delta == (uint64_t)total);
626edb596e8SFlorian Westphal 	close(fd);
627edb596e8SFlorian Westphal }
628edb596e8SFlorian Westphal 
process_one_client(int fd,int pipefd)629edb596e8SFlorian Westphal static void process_one_client(int fd, int pipefd)
630edb596e8SFlorian Westphal {
631edb596e8SFlorian Westphal 	ssize_t ret, ret2, ret3;
632edb596e8SFlorian Westphal 	struct so_state s;
633edb596e8SFlorian Westphal 	char buf[4096];
634edb596e8SFlorian Westphal 
635edb596e8SFlorian Westphal 	memset(&s, 0, sizeof(s));
636edb596e8SFlorian Westphal 	do_getsockopts(&s, fd, 0, 0);
637edb596e8SFlorian Westphal 
638edb596e8SFlorian Westphal 	ret = write(pipefd, "xmit", 4);
639edb596e8SFlorian Westphal 	assert(ret == 4);
640edb596e8SFlorian Westphal 
641edb596e8SFlorian Westphal 	ret = read(fd, buf, sizeof(buf));
642edb596e8SFlorian Westphal 	if (ret < 0)
643ce997912SFlorian Westphal 		die_perror("read");
644ce997912SFlorian Westphal 
645ce997912SFlorian Westphal 	assert(s.mptcpi_rcv_delta <= (uint64_t)ret);
646ce997912SFlorian Westphal 
647ce997912SFlorian Westphal 	if (s.tcpi_rcv_delta)
648ce997912SFlorian Westphal 		assert(s.tcpi_rcv_delta == (uint64_t)ret);
649ce997912SFlorian Westphal 
650ce997912SFlorian Westphal 	ret2 = write(fd, buf, ret);
651ce997912SFlorian Westphal 	if (ret2 < 0)
652ce997912SFlorian Westphal 		die_perror("write");
653ce997912SFlorian Westphal 
654ce997912SFlorian Westphal 	/* wait for hangup */
655ce997912SFlorian Westphal 	ret3 = read(fd, buf, 1);
656ce997912SFlorian Westphal 	if (ret3 != 0)
657ce997912SFlorian Westphal 		xerror("expected EOF, got %lu", ret3);
658ce997912SFlorian Westphal 
659ce997912SFlorian Westphal 	do_getsockopts(&s, fd, ret, ret2);
660edb596e8SFlorian Westphal 	if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
661edb596e8SFlorian Westphal 		xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
662ce997912SFlorian Westphal 
663ce997912SFlorian Westphal 	/* be nice when running on top of older kernel */
664ce997912SFlorian Westphal 	if (s.pkt_stats_avail) {
665ce997912SFlorian Westphal 		if (s.last_sample.mptcpi_bytes_sent != ret2)
666ce997912SFlorian Westphal 			xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64,
667ce997912SFlorian Westphal 			       s.last_sample.mptcpi_bytes_sent, ret2,
668ce997912SFlorian Westphal 			       s.last_sample.mptcpi_bytes_sent - ret2);
669ce997912SFlorian Westphal 		if (s.last_sample.mptcpi_bytes_received != ret)
670ce997912SFlorian Westphal 			xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64,
671ce997912SFlorian Westphal 			       s.last_sample.mptcpi_bytes_received, ret,
672ce997912SFlorian Westphal 			       s.last_sample.mptcpi_bytes_received - ret);
673ce997912SFlorian Westphal 		if (s.last_sample.mptcpi_bytes_acked != ret)
674ce997912SFlorian Westphal 			xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64,
675ce997912SFlorian Westphal 			       s.last_sample.mptcpi_bytes_acked, ret2,
676ce997912SFlorian Westphal 			       s.last_sample.mptcpi_bytes_acked - ret2);
677ce997912SFlorian Westphal 	}
678ce997912SFlorian Westphal 
679ce997912SFlorian Westphal 	close(fd);
680ce997912SFlorian Westphal }
681ce997912SFlorian Westphal 
xaccept(int s)682ce997912SFlorian Westphal static int xaccept(int s)
683ce997912SFlorian Westphal {
684ce997912SFlorian Westphal 	int fd = accept(s, NULL, 0);
685ce997912SFlorian Westphal 
686ce997912SFlorian Westphal 	if (fd < 0)
687ce997912SFlorian Westphal 		die_perror("accept");
688ce997912SFlorian Westphal 
689ce997912SFlorian Westphal 	return fd;
690ce997912SFlorian Westphal }
691ce997912SFlorian Westphal 
server(int pipefd)692ce997912SFlorian Westphal static int server(int pipefd)
693edb596e8SFlorian Westphal {
694edb596e8SFlorian Westphal 	int fd = -1, r;
695edb596e8SFlorian Westphal 
696edb596e8SFlorian Westphal 	switch (pf) {
697edb596e8SFlorian Westphal 	case AF_INET:
698edb596e8SFlorian Westphal 		fd = sock_listen_mptcp("127.0.0.1", "15432");
699edb596e8SFlorian Westphal 		break;
700edb596e8SFlorian Westphal 	case AF_INET6:
701edb596e8SFlorian Westphal 		fd = sock_listen_mptcp("::1", "15432");
702edb596e8SFlorian Westphal 		break;
703edb596e8SFlorian Westphal 	default:
704edb596e8SFlorian Westphal 		xerror("Unknown pf %d\n", pf);
705edb596e8SFlorian Westphal 		break;
706edb596e8SFlorian Westphal 	}
707edb596e8SFlorian Westphal 
708edb596e8SFlorian Westphal 	r = write(pipefd, "conn", 4);
709edb596e8SFlorian Westphal 	assert(r == 4);
710edb596e8SFlorian Westphal 
711edb596e8SFlorian Westphal 	alarm(15);
712ce997912SFlorian Westphal 	r = xaccept(fd);
713ce997912SFlorian Westphal 
714ce997912SFlorian Westphal 	process_one_client(r, pipefd);
715ce997912SFlorian Westphal 
716ce997912SFlorian Westphal 	return 0;
717ce997912SFlorian Westphal }
718ce997912SFlorian Westphal 
test_ip_tos_sockopt(int fd)719ce997912SFlorian Westphal static void test_ip_tos_sockopt(int fd)
720edb596e8SFlorian Westphal {
721edb596e8SFlorian Westphal 	uint8_t tos_in, tos_out;
722ce997912SFlorian Westphal 	socklen_t s;
723ce997912SFlorian Westphal 	int r;
724ce997912SFlorian Westphal 
725ce997912SFlorian Westphal 	tos_in = rand() & 0xfc;
726ce997912SFlorian Westphal 	r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out));
727ce997912SFlorian Westphal 	if (r != 0)
728ce997912SFlorian Westphal 		die_perror("setsockopt IP_TOS");
729ce997912SFlorian Westphal 
730ce997912SFlorian Westphal 	tos_out = 0;
731ce997912SFlorian Westphal 	s = sizeof(tos_out);
732ce997912SFlorian Westphal 	r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
733ce997912SFlorian Westphal 	if (r != 0)
734ce997912SFlorian Westphal 		die_perror("getsockopt IP_TOS");
735ce997912SFlorian Westphal 
736ce997912SFlorian Westphal 	if (tos_in != tos_out)
737ce997912SFlorian Westphal 		xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s);
738ce997912SFlorian Westphal 
739ce997912SFlorian Westphal 	if (s != 1)
740ce997912SFlorian Westphal 		xerror("tos should be 1 byte");
741ce997912SFlorian Westphal 
742ce997912SFlorian Westphal 	s = 0;
743ce997912SFlorian Westphal 	r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
744ce997912SFlorian Westphal 	if (r != 0)
745ce997912SFlorian Westphal 		die_perror("getsockopt IP_TOS 0");
746ce997912SFlorian Westphal 	if (s != 0)
747ce997912SFlorian Westphal 		xerror("expect socklen_t == 0");
748ce997912SFlorian Westphal 
749ce997912SFlorian Westphal 	s = -1;
750ce997912SFlorian Westphal 	r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
751ce997912SFlorian Westphal 	if (r != -1 && errno != EINVAL)
752ce997912SFlorian Westphal 		die_perror("getsockopt IP_TOS did not indicate -EINVAL");
753 	if (s != -1)
754 		xerror("expect socklen_t == -1");
755 }
756 
client(int pipefd)757 static int client(int pipefd)
758 {
759 	int fd = -1;
760 
761 	alarm(15);
762 
763 	switch (pf) {
764 	case AF_INET:
765 		fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
766 		break;
767 	case AF_INET6:
768 		fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP);
769 		break;
770 	default:
771 		xerror("Unknown pf %d\n", pf);
772 	}
773 
774 	test_ip_tos_sockopt(fd);
775 
776 	connect_one_server(fd, pipefd);
777 
778 	return 0;
779 }
780 
xfork(void)781 static pid_t xfork(void)
782 {
783 	pid_t p = fork();
784 
785 	if (p < 0)
786 		die_perror("fork");
787 
788 	return p;
789 }
790 
rcheck(int wstatus,const char * what)791 static int rcheck(int wstatus, const char *what)
792 {
793 	if (WIFEXITED(wstatus)) {
794 		if (WEXITSTATUS(wstatus) == 0)
795 			return 0;
796 		fprintf(stderr, "%s exited, status=%d\n", what, WEXITSTATUS(wstatus));
797 		return WEXITSTATUS(wstatus);
798 	} else if (WIFSIGNALED(wstatus)) {
799 		xerror("%s killed by signal %d\n", what, WTERMSIG(wstatus));
800 	} else if (WIFSTOPPED(wstatus)) {
801 		xerror("%s stopped by signal %d\n", what, WSTOPSIG(wstatus));
802 	}
803 
804 	return 111;
805 }
806 
init_rng(void)807 static void init_rng(void)
808 {
809 	int fd = open("/dev/urandom", O_RDONLY);
810 
811 	if (fd >= 0) {
812 		unsigned int foo;
813 		ssize_t ret;
814 
815 		/* can't fail */
816 		ret = read(fd, &foo, sizeof(foo));
817 		assert(ret == sizeof(foo));
818 
819 		close(fd);
820 		srand(foo);
821 	} else {
822 		srand(time(NULL));
823 	}
824 }
825 
main(int argc,char * argv[])826 int main(int argc, char *argv[])
827 {
828 	int e1, e2, wstatus;
829 	pid_t s, c, ret;
830 	int pipefds[2];
831 
832 	parse_opts(argc, argv);
833 
834 	init_rng();
835 
836 	e1 = pipe(pipefds);
837 	if (e1 < 0)
838 		die_perror("pipe");
839 
840 	s = xfork();
841 	if (s == 0)
842 		return server(pipefds[1]);
843 
844 	close(pipefds[1]);
845 
846 	/* wait until server bound a socket */
847 	e1 = read(pipefds[0], &e1, 4);
848 	assert(e1 == 4);
849 
850 	c = xfork();
851 	if (c == 0)
852 		return client(pipefds[0]);
853 
854 	close(pipefds[0]);
855 
856 	ret = waitpid(s, &wstatus, 0);
857 	if (ret == -1)
858 		die_perror("waitpid");
859 	e1 = rcheck(wstatus, "server");
860 	ret = waitpid(c, &wstatus, 0);
861 	if (ret == -1)
862 		die_perror("waitpid");
863 	e2 = rcheck(wstatus, "client");
864 
865 	return e1 ? e1 : e2;
866 }
867