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