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