Merge tag 'sched_ext-for-6.12-rc1-fixes-1' of git://git.kernel.org/pub/scm/linux...
[linux-block.git] / tools / testing / selftests / net / mptcp / mptcp_sockopt.c
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                          const struct addrinfo *hints,
163                          struct addrinfo **res)
164 {
165         int err = getaddrinfo(node, service, hints, res);
166
167         if (err) {
168                 const char *errstr = getxinfo_strerr(err);
169
170                 fprintf(stderr, "Fatal: getaddrinfo(%s:%s): %s\n",
171                         node ? node : "", service ? service : "", errstr);
172                 exit(1);
173         }
174 }
175
176 static int sock_listen_mptcp(const char * const listenaddr,
177                              const char * const port)
178 {
179         int sock = -1;
180         struct addrinfo hints = {
181                 .ai_protocol = IPPROTO_TCP,
182                 .ai_socktype = SOCK_STREAM,
183                 .ai_flags = AI_PASSIVE | AI_NUMERICHOST
184         };
185
186         hints.ai_family = pf;
187
188         struct addrinfo *a, *addr;
189         int one = 1;
190
191         xgetaddrinfo(listenaddr, port, &hints, &addr);
192         hints.ai_family = pf;
193
194         for (a = addr; a; a = a->ai_next) {
195                 sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
196                 if (sock < 0)
197                         continue;
198
199                 if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
200                                      sizeof(one)))
201                         perror("setsockopt");
202
203                 if (bind(sock, a->ai_addr, a->ai_addrlen) == 0)
204                         break; /* success */
205
206                 perror("bind");
207                 close(sock);
208                 sock = -1;
209         }
210
211         freeaddrinfo(addr);
212
213         if (sock < 0)
214                 xerror("could not create listen socket");
215
216         if (listen(sock, 20))
217                 die_perror("listen");
218
219         return sock;
220 }
221
222 static int sock_connect_mptcp(const char * const remoteaddr,
223                               const char * const port, int proto)
224 {
225         struct addrinfo hints = {
226                 .ai_protocol = IPPROTO_TCP,
227                 .ai_socktype = SOCK_STREAM,
228         };
229         struct addrinfo *a, *addr;
230         int sock = -1;
231
232         hints.ai_family = pf;
233
234         xgetaddrinfo(remoteaddr, port, &hints, &addr);
235         for (a = addr; a; a = a->ai_next) {
236                 sock = socket(a->ai_family, a->ai_socktype, proto);
237                 if (sock < 0)
238                         continue;
239
240                 if (connect(sock, a->ai_addr, a->ai_addrlen) == 0)
241                         break; /* success */
242
243                 die_perror("connect");
244         }
245
246         if (sock < 0)
247                 xerror("could not create connect socket");
248
249         freeaddrinfo(addr);
250         return sock;
251 }
252
253 static void parse_opts(int argc, char **argv)
254 {
255         int c;
256
257         while ((c = getopt(argc, argv, "h6")) != -1) {
258                 switch (c) {
259                 case 'h':
260                         die_usage(0);
261                         break;
262                 case '6':
263                         pf = AF_INET6;
264                         break;
265                 default:
266                         die_usage(1);
267                         break;
268                 }
269         }
270 }
271
272 static void do_getsockopt_bogus_sf_data(int fd, int optname)
273 {
274         struct mptcp_subflow_data good_data;
275         struct bogus_data {
276                 struct mptcp_subflow_data d;
277                 char buf[2];
278         } bd;
279         socklen_t olen, _olen;
280         int ret;
281
282         memset(&bd, 0, sizeof(bd));
283         memset(&good_data, 0, sizeof(good_data));
284
285         olen = sizeof(good_data);
286         good_data.size_subflow_data = olen;
287
288         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
289         assert(ret < 0); /* 0 size_subflow_data */
290         assert(olen == sizeof(good_data));
291
292         bd.d = good_data;
293
294         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
295         assert(ret == 0);
296         assert(olen == sizeof(good_data));
297         assert(bd.d.num_subflows == 1);
298         assert(bd.d.size_kernel > 0);
299         assert(bd.d.size_user == 0);
300
301         bd.d = good_data;
302         _olen = rand() % olen;
303         olen = _olen;
304         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
305         assert(ret < 0);        /* bogus olen */
306         assert(olen == _olen);  /* must be unchanged */
307
308         bd.d = good_data;
309         olen = sizeof(good_data);
310         bd.d.size_kernel = 1;
311         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
312         assert(ret < 0); /* size_kernel not 0 */
313
314         bd.d = good_data;
315         olen = sizeof(good_data);
316         bd.d.num_subflows = 1;
317         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
318         assert(ret < 0); /* num_subflows not 0 */
319
320         /* forward compat check: larger struct mptcp_subflow_data on 'old' kernel */
321         bd.d = good_data;
322         olen = sizeof(bd);
323         bd.d.size_subflow_data = sizeof(bd);
324
325         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &olen);
326         assert(ret == 0);
327
328         /* olen must be truncated to real data size filled by kernel: */
329         assert(olen == sizeof(good_data));
330
331         assert(bd.d.size_subflow_data == sizeof(bd));
332
333         bd.d = good_data;
334         bd.d.size_subflow_data += 1;
335         bd.d.size_user = 1;
336         olen = bd.d.size_subflow_data + 1;
337         _olen = olen;
338
339         ret = getsockopt(fd, SOL_MPTCP, optname, &bd, &_olen);
340         assert(ret == 0);
341
342         /* no truncation, kernel should have filled 1 byte of optname payload in buf[1]: */
343         assert(olen == _olen);
344
345         assert(bd.d.size_subflow_data == sizeof(good_data) + 1);
346         assert(bd.buf[0] == 0);
347 }
348
349 static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
350 {
351         struct mptcp_info i;
352         socklen_t olen;
353         int ret;
354
355         olen = sizeof(i);
356         ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen);
357
358         if (ret < 0)
359                 die_perror("getsockopt MPTCP_INFO");
360
361         s->pkt_stats_avail = olen >= sizeof(i);
362
363         s->last_sample = i;
364         if (s->mi.mptcpi_write_seq == 0)
365                 s->mi = i;
366
367         assert(s->mi.mptcpi_write_seq + w == i.mptcpi_write_seq);
368
369         s->mptcpi_rcv_delta = i.mptcpi_rcv_nxt - s->mi.mptcpi_rcv_nxt;
370 }
371
372 static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t w)
373 {
374         struct my_tcp_info {
375                 struct mptcp_subflow_data d;
376                 struct tcp_info ti[2];
377         } ti;
378         int ret, tries = 5;
379         socklen_t olen;
380
381         do {
382                 memset(&ti, 0, sizeof(ti));
383
384                 ti.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
385                 ti.d.size_user = sizeof(struct tcp_info);
386                 olen = sizeof(ti);
387
388                 ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen);
389                 if (ret < 0)
390                         xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
391
392                 assert(olen <= sizeof(ti));
393                 assert(ti.d.size_kernel > 0);
394                 assert(ti.d.size_user ==
395                        MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
396                 assert(ti.d.num_subflows == 1);
397
398                 assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
399                 olen -= sizeof(struct mptcp_subflow_data);
400                 assert(olen == ti.d.size_user);
401
402                 s->tcp_info = ti.ti[0];
403
404                 if (ti.ti[0].tcpi_bytes_sent == w &&
405                     ti.ti[0].tcpi_bytes_received == r)
406                         goto done;
407
408                 if (r == 0 && ti.ti[0].tcpi_bytes_sent == w &&
409                     ti.ti[0].tcpi_bytes_received) {
410                         s->tcpi_rcv_delta = ti.ti[0].tcpi_bytes_received;
411                         goto done;
412                 }
413
414                 /* wait and repeat, might be that tx is still ongoing */
415                 sleep(1);
416         } while (tries-- > 0);
417
418         xerror("tcpi_bytes_sent %" PRIu64 ", want %zu. tcpi_bytes_received %" PRIu64 ", want %zu",
419                 ti.ti[0].tcpi_bytes_sent, w, ti.ti[0].tcpi_bytes_received, r);
420
421 done:
422         do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
423 }
424
425 static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
426 {
427         struct sockaddr_storage remote, local;
428         socklen_t olen, rlen, llen;
429         int ret;
430         struct my_addrs {
431                 struct mptcp_subflow_data d;
432                 struct mptcp_subflow_addrs addr[2];
433         } addrs;
434
435         memset(&addrs, 0, sizeof(addrs));
436         memset(&local, 0, sizeof(local));
437         memset(&remote, 0, sizeof(remote));
438
439         addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
440         addrs.d.size_user = sizeof(struct mptcp_subflow_addrs);
441         olen = sizeof(addrs);
442
443         ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
444         if (ret < 0)
445                 die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
446
447         assert(olen <= sizeof(addrs));
448         assert(addrs.d.size_kernel > 0);
449         assert(addrs.d.size_user ==
450                MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
451         assert(addrs.d.num_subflows == 1);
452
453         assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
454         olen -= sizeof(struct mptcp_subflow_data);
455         assert(olen == addrs.d.size_user);
456
457         llen = sizeof(local);
458         ret = getsockname(fd, (struct sockaddr *)&local, &llen);
459         if (ret < 0)
460                 die_perror("getsockname");
461         rlen = sizeof(remote);
462         ret = getpeername(fd, (struct sockaddr *)&remote, &rlen);
463         if (ret < 0)
464                 die_perror("getpeername");
465
466         assert(rlen > 0);
467         assert(rlen == llen);
468
469         assert(remote.ss_family == local.ss_family);
470
471         assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
472         assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
473         s->addrs = addrs.addr[0];
474
475         memset(&addrs, 0, sizeof(addrs));
476
477         addrs.d.size_subflow_data = sizeof(struct mptcp_subflow_data);
478         addrs.d.size_user = sizeof(sa_family_t);
479         olen = sizeof(addrs.d) + sizeof(sa_family_t);
480
481         ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
482         assert(ret == 0);
483         assert(olen == sizeof(addrs.d) + sizeof(sa_family_t));
484
485         assert(addrs.addr[0].sa_family == pf);
486         assert(addrs.addr[0].sa_family == local.ss_family);
487
488         assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) != 0);
489         assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) != 0);
490
491         do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
492 }
493
494 static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
495 {
496         size_t data_size = sizeof(struct mptcp_full_info);
497         struct mptcp_subflow_info sfinfo[2];
498         struct tcp_info tcp_info[2];
499         struct mptcp_full_info mfi;
500         socklen_t olen;
501         int ret;
502
503         memset(&mfi, 0, data_size);
504         memset(tcp_info, 0, sizeof(tcp_info));
505         memset(sfinfo, 0, sizeof(sfinfo));
506
507         mfi.size_tcpinfo_user = sizeof(struct tcp_info);
508         mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info);
509         mfi.size_arrays_user = 2;
510         mfi.subflow_info = (unsigned long)&sfinfo[0];
511         mfi.tcp_info = (unsigned long)&tcp_info[0];
512         olen = data_size;
513
514         ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
515         if (ret < 0) {
516                 if (errno == EOPNOTSUPP) {
517                         perror("MPTCP_FULL_INFO test skipped");
518                         return;
519                 }
520                 xerror("getsockopt MPTCP_FULL_INFO");
521         }
522
523         assert(olen <= data_size);
524         assert(mfi.size_tcpinfo_kernel > 0);
525         assert(mfi.size_tcpinfo_user ==
526                MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info)));
527         assert(mfi.size_sfinfo_kernel > 0);
528         assert(mfi.size_sfinfo_user ==
529                MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info)));
530         assert(mfi.num_subflows == 1);
531
532         /* Tolerate future extension to mptcp_info struct and running newer
533          * test on top of older kernel.
534          * Anyway any kernel supporting MPTCP_FULL_INFO must at least include
535          * the following in mptcp_info.
536          */
537         assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info));
538         assert(mfi.mptcp_info.mptcpi_subflows == 0);
539         assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent);
540         assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received);
541
542         assert(sfinfo[0].id == 1);
543         assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent);
544         assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received);
545         assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs)));
546 }
547
548 static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
549 {
550         do_getsockopt_mptcp_info(s, fd, w);
551
552         do_getsockopt_tcp_info(s, fd, r, w);
553
554         do_getsockopt_subflow_addrs(s, fd);
555
556         if (r)
557                 do_getsockopt_mptcp_full_info(s, fd);
558 }
559
560 static void connect_one_server(int fd, int pipefd)
561 {
562         char buf[4096], buf2[4096];
563         size_t len, i, total;
564         struct so_state s;
565         bool eof = false;
566         ssize_t ret;
567
568         memset(&s, 0, sizeof(s));
569
570         len = rand() % (sizeof(buf) - 1);
571
572         if (len < 128)
573                 len = 128;
574
575         for (i = 0; i < len ; i++) {
576                 buf[i] = rand() % 26;
577                 buf[i] += 'A';
578         }
579
580         buf[i] = '\n';
581
582         do_getsockopts(&s, fd, 0, 0);
583
584         /* un-block server */
585         ret = read(pipefd, buf2, 4);
586         assert(ret == 4);
587         close(pipefd);
588
589         assert(strncmp(buf2, "xmit", 4) == 0);
590
591         ret = write(fd, buf, len);
592         if (ret < 0)
593                 die_perror("write");
594
595         if (ret != (ssize_t)len)
596                 xerror("short write");
597
598         total = 0;
599         do {
600                 ret = read(fd, buf2 + total, sizeof(buf2) - total);
601                 if (ret < 0)
602                         die_perror("read");
603                 if (ret == 0) {
604                         eof = true;
605                         break;
606                 }
607
608                 total += ret;
609         } while (total < len);
610
611         if (total != len)
612                 xerror("total %lu, len %lu eof %d\n", total, len, eof);
613
614         if (memcmp(buf, buf2, len))
615                 xerror("data corruption");
616
617         if (s.tcpi_rcv_delta)
618                 assert(s.tcpi_rcv_delta <= total);
619
620         do_getsockopts(&s, fd, ret, ret);
621
622         if (eof)
623                 total += 1; /* sequence advances due to FIN */
624
625         assert(s.mptcpi_rcv_delta == (uint64_t)total);
626         close(fd);
627 }
628
629 static void process_one_client(int fd, int pipefd)
630 {
631         ssize_t ret, ret2, ret3;
632         struct so_state s;
633         char buf[4096];
634
635         memset(&s, 0, sizeof(s));
636         do_getsockopts(&s, fd, 0, 0);
637
638         ret = write(pipefd, "xmit", 4);
639         assert(ret == 4);
640
641         ret = read(fd, buf, sizeof(buf));
642         if (ret < 0)
643                 die_perror("read");
644
645         assert(s.mptcpi_rcv_delta <= (uint64_t)ret);
646
647         if (s.tcpi_rcv_delta)
648                 assert(s.tcpi_rcv_delta == (uint64_t)ret);
649
650         ret2 = write(fd, buf, ret);
651         if (ret2 < 0)
652                 die_perror("write");
653
654         /* wait for hangup */
655         ret3 = read(fd, buf, 1);
656         if (ret3 != 0)
657                 xerror("expected EOF, got %lu", ret3);
658
659         do_getsockopts(&s, fd, ret, ret2);
660         if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
661                 xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret);
662
663         /* be nice when running on top of older kernel */
664         if (s.pkt_stats_avail) {
665                 if (s.last_sample.mptcpi_bytes_sent != ret2)
666                         xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64,
667                                s.last_sample.mptcpi_bytes_sent, ret2,
668                                s.last_sample.mptcpi_bytes_sent - ret2);
669                 if (s.last_sample.mptcpi_bytes_received != ret)
670                         xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64,
671                                s.last_sample.mptcpi_bytes_received, ret,
672                                s.last_sample.mptcpi_bytes_received - ret);
673                 if (s.last_sample.mptcpi_bytes_acked != ret)
674                         xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64,
675                                s.last_sample.mptcpi_bytes_acked, ret2,
676                                s.last_sample.mptcpi_bytes_acked - ret2);
677         }
678
679         close(fd);
680 }
681
682 static int xaccept(int s)
683 {
684         int fd = accept(s, NULL, 0);
685
686         if (fd < 0)
687                 die_perror("accept");
688
689         return fd;
690 }
691
692 static int server(int pipefd)
693 {
694         int fd = -1, r;
695
696         switch (pf) {
697         case AF_INET:
698                 fd = sock_listen_mptcp("127.0.0.1", "15432");
699                 break;
700         case AF_INET6:
701                 fd = sock_listen_mptcp("::1", "15432");
702                 break;
703         default:
704                 xerror("Unknown pf %d\n", pf);
705                 break;
706         }
707
708         r = write(pipefd, "conn", 4);
709         assert(r == 4);
710
711         alarm(15);
712         r = xaccept(fd);
713
714         process_one_client(r, pipefd);
715
716         return 0;
717 }
718
719 static void test_ip_tos_sockopt(int fd)
720 {
721         uint8_t tos_in, tos_out;
722         socklen_t s;
723         int r;
724
725         tos_in = rand() & 0xfc;
726         r = setsockopt(fd, SOL_IP, IP_TOS, &tos_in, sizeof(tos_out));
727         if (r != 0)
728                 die_perror("setsockopt IP_TOS");
729
730         tos_out = 0;
731         s = sizeof(tos_out);
732         r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
733         if (r != 0)
734                 die_perror("getsockopt IP_TOS");
735
736         if (tos_in != tos_out)
737                 xerror("tos %x != %x socklen_t %d\n", tos_in, tos_out, s);
738
739         if (s != 1)
740                 xerror("tos should be 1 byte");
741
742         s = 0;
743         r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
744         if (r != 0)
745                 die_perror("getsockopt IP_TOS 0");
746         if (s != 0)
747                 xerror("expect socklen_t == 0");
748
749         s = -1;
750         r = getsockopt(fd, SOL_IP, IP_TOS, &tos_out, &s);
751         if (r != -1 && errno != EINVAL)
752                 die_perror("getsockopt IP_TOS did not indicate -EINVAL");
753         if (s != -1)
754                 xerror("expect socklen_t == -1");
755 }
756
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
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
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
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
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 }