1*5ef5c90eSJian Yang #include <errno.h> 2*5ef5c90eSJian Yang #include <error.h> 3*5ef5c90eSJian Yang #include <getopt.h> 4*5ef5c90eSJian Yang #include <stdbool.h> 5*5ef5c90eSJian Yang #include <stdio.h> 6*5ef5c90eSJian Yang #include <stdlib.h> 7*5ef5c90eSJian Yang #include <string.h> 8*5ef5c90eSJian Yang #include <unistd.h> 9*5ef5c90eSJian Yang 10*5ef5c90eSJian Yang #include <sys/time.h> 11*5ef5c90eSJian Yang #include <sys/socket.h> 12*5ef5c90eSJian Yang #include <sys/select.h> 13*5ef5c90eSJian Yang #include <sys/ioctl.h> 14*5ef5c90eSJian Yang #include <arpa/inet.h> 15*5ef5c90eSJian Yang #include <net/if.h> 16*5ef5c90eSJian Yang 17*5ef5c90eSJian Yang #include <asm/types.h> 18*5ef5c90eSJian Yang #include <linux/net_tstamp.h> 19*5ef5c90eSJian Yang #include <linux/errqueue.h> 20*5ef5c90eSJian Yang 21*5ef5c90eSJian Yang #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 22*5ef5c90eSJian Yang 23*5ef5c90eSJian Yang struct options { 24*5ef5c90eSJian Yang int so_timestamp; 25*5ef5c90eSJian Yang int so_timestampns; 26*5ef5c90eSJian Yang int so_timestamping; 27*5ef5c90eSJian Yang }; 28*5ef5c90eSJian Yang 29*5ef5c90eSJian Yang struct tstamps { 30*5ef5c90eSJian Yang bool tstamp; 31*5ef5c90eSJian Yang bool tstampns; 32*5ef5c90eSJian Yang bool swtstamp; 33*5ef5c90eSJian Yang bool hwtstamp; 34*5ef5c90eSJian Yang }; 35*5ef5c90eSJian Yang 36*5ef5c90eSJian Yang struct socket_type { 37*5ef5c90eSJian Yang char *friendly_name; 38*5ef5c90eSJian Yang int type; 39*5ef5c90eSJian Yang int protocol; 40*5ef5c90eSJian Yang bool enabled; 41*5ef5c90eSJian Yang }; 42*5ef5c90eSJian Yang 43*5ef5c90eSJian Yang struct test_case { 44*5ef5c90eSJian Yang struct options sockopt; 45*5ef5c90eSJian Yang struct tstamps expected; 46*5ef5c90eSJian Yang bool enabled; 47*5ef5c90eSJian Yang }; 48*5ef5c90eSJian Yang 49*5ef5c90eSJian Yang struct sof_flag { 50*5ef5c90eSJian Yang int mask; 51*5ef5c90eSJian Yang char *name; 52*5ef5c90eSJian Yang }; 53*5ef5c90eSJian Yang 54*5ef5c90eSJian Yang static struct sof_flag sof_flags[] = { 55*5ef5c90eSJian Yang #define SOF_FLAG(f) { f, #f } 56*5ef5c90eSJian Yang SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE), 57*5ef5c90eSJian Yang SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE), 58*5ef5c90eSJian Yang SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE), 59*5ef5c90eSJian Yang }; 60*5ef5c90eSJian Yang 61*5ef5c90eSJian Yang static struct socket_type socket_types[] = { 62*5ef5c90eSJian Yang { "ip", SOCK_RAW, IPPROTO_EGP }, 63*5ef5c90eSJian Yang { "udp", SOCK_DGRAM, IPPROTO_UDP }, 64*5ef5c90eSJian Yang { "tcp", SOCK_STREAM, IPPROTO_TCP }, 65*5ef5c90eSJian Yang }; 66*5ef5c90eSJian Yang 67*5ef5c90eSJian Yang static struct test_case test_cases[] = { 68*5ef5c90eSJian Yang { {}, {} }, 69*5ef5c90eSJian Yang { 70*5ef5c90eSJian Yang { so_timestamp: 1 }, 71*5ef5c90eSJian Yang { tstamp: true } 72*5ef5c90eSJian Yang }, 73*5ef5c90eSJian Yang { 74*5ef5c90eSJian Yang { so_timestampns: 1 }, 75*5ef5c90eSJian Yang { tstampns: true } 76*5ef5c90eSJian Yang }, 77*5ef5c90eSJian Yang { 78*5ef5c90eSJian Yang { so_timestamp: 1, so_timestampns: 1 }, 79*5ef5c90eSJian Yang { tstampns: true } 80*5ef5c90eSJian Yang }, 81*5ef5c90eSJian Yang { 82*5ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE }, 83*5ef5c90eSJian Yang {} 84*5ef5c90eSJian Yang }, 85*5ef5c90eSJian Yang { 86*5ef5c90eSJian Yang /* Loopback device does not support hw timestamps. */ 87*5ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_RX_HARDWARE }, 88*5ef5c90eSJian Yang {} 89*5ef5c90eSJian Yang }, 90*5ef5c90eSJian Yang { 91*5ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_SOFTWARE }, 92*5ef5c90eSJian Yang {} 93*5ef5c90eSJian Yang }, 94*5ef5c90eSJian Yang { 95*5ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE 96*5ef5c90eSJian Yang | SOF_TIMESTAMPING_RX_HARDWARE }, 97*5ef5c90eSJian Yang {} 98*5ef5c90eSJian Yang }, 99*5ef5c90eSJian Yang { 100*5ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_SOFTWARE 101*5ef5c90eSJian Yang | SOF_TIMESTAMPING_RX_SOFTWARE }, 102*5ef5c90eSJian Yang { swtstamp: true } 103*5ef5c90eSJian Yang }, 104*5ef5c90eSJian Yang { 105*5ef5c90eSJian Yang { so_timestamp: 1, so_timestamping: SOF_TIMESTAMPING_SOFTWARE 106*5ef5c90eSJian Yang | SOF_TIMESTAMPING_RX_SOFTWARE }, 107*5ef5c90eSJian Yang { tstamp: true, swtstamp: true } 108*5ef5c90eSJian Yang }, 109*5ef5c90eSJian Yang }; 110*5ef5c90eSJian Yang 111*5ef5c90eSJian Yang static struct option long_options[] = { 112*5ef5c90eSJian Yang { "list_tests", no_argument, 0, 'l' }, 113*5ef5c90eSJian Yang { "test_num", required_argument, 0, 'n' }, 114*5ef5c90eSJian Yang { "op_size", required_argument, 0, 's' }, 115*5ef5c90eSJian Yang { "tcp", no_argument, 0, 't' }, 116*5ef5c90eSJian Yang { "udp", no_argument, 0, 'u' }, 117*5ef5c90eSJian Yang { "ip", no_argument, 0, 'i' }, 118*5ef5c90eSJian Yang }; 119*5ef5c90eSJian Yang 120*5ef5c90eSJian Yang static int next_port = 19999; 121*5ef5c90eSJian Yang static int op_size = 10 * 1024; 122*5ef5c90eSJian Yang 123*5ef5c90eSJian Yang void print_test_case(struct test_case *t) 124*5ef5c90eSJian Yang { 125*5ef5c90eSJian Yang int f = 0; 126*5ef5c90eSJian Yang 127*5ef5c90eSJian Yang printf("sockopts {"); 128*5ef5c90eSJian Yang if (t->sockopt.so_timestamp) 129*5ef5c90eSJian Yang printf(" SO_TIMESTAMP "); 130*5ef5c90eSJian Yang if (t->sockopt.so_timestampns) 131*5ef5c90eSJian Yang printf(" SO_TIMESTAMPNS "); 132*5ef5c90eSJian Yang if (t->sockopt.so_timestamping) { 133*5ef5c90eSJian Yang printf(" SO_TIMESTAMPING: {"); 134*5ef5c90eSJian Yang for (f = 0; f < ARRAY_SIZE(sof_flags); f++) 135*5ef5c90eSJian Yang if (t->sockopt.so_timestamping & sof_flags[f].mask) 136*5ef5c90eSJian Yang printf(" %s |", sof_flags[f].name); 137*5ef5c90eSJian Yang printf("}"); 138*5ef5c90eSJian Yang } 139*5ef5c90eSJian Yang printf("} expected cmsgs: {"); 140*5ef5c90eSJian Yang if (t->expected.tstamp) 141*5ef5c90eSJian Yang printf(" SCM_TIMESTAMP "); 142*5ef5c90eSJian Yang if (t->expected.tstampns) 143*5ef5c90eSJian Yang printf(" SCM_TIMESTAMPNS "); 144*5ef5c90eSJian Yang if (t->expected.swtstamp || t->expected.hwtstamp) { 145*5ef5c90eSJian Yang printf(" SCM_TIMESTAMPING {"); 146*5ef5c90eSJian Yang if (t->expected.swtstamp) 147*5ef5c90eSJian Yang printf("0"); 148*5ef5c90eSJian Yang if (t->expected.swtstamp && t->expected.hwtstamp) 149*5ef5c90eSJian Yang printf(","); 150*5ef5c90eSJian Yang if (t->expected.hwtstamp) 151*5ef5c90eSJian Yang printf("2"); 152*5ef5c90eSJian Yang printf("}"); 153*5ef5c90eSJian Yang } 154*5ef5c90eSJian Yang printf("}\n"); 155*5ef5c90eSJian Yang } 156*5ef5c90eSJian Yang 157*5ef5c90eSJian Yang void do_send(int src) 158*5ef5c90eSJian Yang { 159*5ef5c90eSJian Yang int r; 160*5ef5c90eSJian Yang char *buf = malloc(op_size); 161*5ef5c90eSJian Yang 162*5ef5c90eSJian Yang memset(buf, 'z', op_size); 163*5ef5c90eSJian Yang r = write(src, buf, op_size); 164*5ef5c90eSJian Yang if (r < 0) 165*5ef5c90eSJian Yang error(1, errno, "Failed to sendmsg"); 166*5ef5c90eSJian Yang 167*5ef5c90eSJian Yang free(buf); 168*5ef5c90eSJian Yang } 169*5ef5c90eSJian Yang 170*5ef5c90eSJian Yang bool do_recv(int rcv, int read_size, struct tstamps expected) 171*5ef5c90eSJian Yang { 172*5ef5c90eSJian Yang const int CMSG_SIZE = 1024; 173*5ef5c90eSJian Yang 174*5ef5c90eSJian Yang struct scm_timestamping *ts; 175*5ef5c90eSJian Yang struct tstamps actual = {}; 176*5ef5c90eSJian Yang char cmsg_buf[CMSG_SIZE]; 177*5ef5c90eSJian Yang struct iovec recv_iov; 178*5ef5c90eSJian Yang struct cmsghdr *cmsg; 179*5ef5c90eSJian Yang bool failed = false; 180*5ef5c90eSJian Yang struct msghdr hdr; 181*5ef5c90eSJian Yang int flags = 0; 182*5ef5c90eSJian Yang int r; 183*5ef5c90eSJian Yang 184*5ef5c90eSJian Yang memset(&hdr, 0, sizeof(hdr)); 185*5ef5c90eSJian Yang hdr.msg_iov = &recv_iov; 186*5ef5c90eSJian Yang hdr.msg_iovlen = 1; 187*5ef5c90eSJian Yang recv_iov.iov_base = malloc(read_size); 188*5ef5c90eSJian Yang recv_iov.iov_len = read_size; 189*5ef5c90eSJian Yang 190*5ef5c90eSJian Yang hdr.msg_control = cmsg_buf; 191*5ef5c90eSJian Yang hdr.msg_controllen = sizeof(cmsg_buf); 192*5ef5c90eSJian Yang 193*5ef5c90eSJian Yang r = recvmsg(rcv, &hdr, flags); 194*5ef5c90eSJian Yang if (r < 0) 195*5ef5c90eSJian Yang error(1, errno, "Failed to recvmsg"); 196*5ef5c90eSJian Yang if (r != read_size) 197*5ef5c90eSJian Yang error(1, 0, "Only received %d bytes of payload.", r); 198*5ef5c90eSJian Yang 199*5ef5c90eSJian Yang if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) 200*5ef5c90eSJian Yang error(1, 0, "Message was truncated."); 201*5ef5c90eSJian Yang 202*5ef5c90eSJian Yang for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; 203*5ef5c90eSJian Yang cmsg = CMSG_NXTHDR(&hdr, cmsg)) { 204*5ef5c90eSJian Yang if (cmsg->cmsg_level != SOL_SOCKET) 205*5ef5c90eSJian Yang error(1, 0, "Unexpected cmsg_level %d", 206*5ef5c90eSJian Yang cmsg->cmsg_level); 207*5ef5c90eSJian Yang switch (cmsg->cmsg_type) { 208*5ef5c90eSJian Yang case SCM_TIMESTAMP: 209*5ef5c90eSJian Yang actual.tstamp = true; 210*5ef5c90eSJian Yang break; 211*5ef5c90eSJian Yang case SCM_TIMESTAMPNS: 212*5ef5c90eSJian Yang actual.tstampns = true; 213*5ef5c90eSJian Yang break; 214*5ef5c90eSJian Yang case SCM_TIMESTAMPING: 215*5ef5c90eSJian Yang ts = (struct scm_timestamping *)CMSG_DATA(cmsg); 216*5ef5c90eSJian Yang actual.swtstamp = !!ts->ts[0].tv_sec; 217*5ef5c90eSJian Yang if (ts->ts[1].tv_sec != 0) 218*5ef5c90eSJian Yang error(0, 0, "ts[1] should not be set."); 219*5ef5c90eSJian Yang actual.hwtstamp = !!ts->ts[2].tv_sec; 220*5ef5c90eSJian Yang break; 221*5ef5c90eSJian Yang default: 222*5ef5c90eSJian Yang error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type); 223*5ef5c90eSJian Yang } 224*5ef5c90eSJian Yang } 225*5ef5c90eSJian Yang 226*5ef5c90eSJian Yang #define VALIDATE(field) \ 227*5ef5c90eSJian Yang do { \ 228*5ef5c90eSJian Yang if (expected.field != actual.field) { \ 229*5ef5c90eSJian Yang if (expected.field) \ 230*5ef5c90eSJian Yang error(0, 0, "Expected " #field " to be set."); \ 231*5ef5c90eSJian Yang else \ 232*5ef5c90eSJian Yang error(0, 0, \ 233*5ef5c90eSJian Yang "Expected " #field " to not be set."); \ 234*5ef5c90eSJian Yang failed = true; \ 235*5ef5c90eSJian Yang } \ 236*5ef5c90eSJian Yang } while (0) 237*5ef5c90eSJian Yang 238*5ef5c90eSJian Yang VALIDATE(tstamp); 239*5ef5c90eSJian Yang VALIDATE(tstampns); 240*5ef5c90eSJian Yang VALIDATE(swtstamp); 241*5ef5c90eSJian Yang VALIDATE(hwtstamp); 242*5ef5c90eSJian Yang #undef VALIDATE 243*5ef5c90eSJian Yang 244*5ef5c90eSJian Yang free(recv_iov.iov_base); 245*5ef5c90eSJian Yang 246*5ef5c90eSJian Yang return failed; 247*5ef5c90eSJian Yang } 248*5ef5c90eSJian Yang 249*5ef5c90eSJian Yang void config_so_flags(int rcv, struct options o) 250*5ef5c90eSJian Yang { 251*5ef5c90eSJian Yang int on = 1; 252*5ef5c90eSJian Yang 253*5ef5c90eSJian Yang if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 254*5ef5c90eSJian Yang error(1, errno, "Failed to enable SO_REUSEADDR"); 255*5ef5c90eSJian Yang 256*5ef5c90eSJian Yang if (o.so_timestamp && 257*5ef5c90eSJian Yang setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP, 258*5ef5c90eSJian Yang &o.so_timestamp, sizeof(o.so_timestamp)) < 0) 259*5ef5c90eSJian Yang error(1, errno, "Failed to enable SO_TIMESTAMP"); 260*5ef5c90eSJian Yang 261*5ef5c90eSJian Yang if (o.so_timestampns && 262*5ef5c90eSJian Yang setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS, 263*5ef5c90eSJian Yang &o.so_timestampns, sizeof(o.so_timestampns)) < 0) 264*5ef5c90eSJian Yang error(1, errno, "Failed to enable SO_TIMESTAMPNS"); 265*5ef5c90eSJian Yang 266*5ef5c90eSJian Yang if (o.so_timestamping && 267*5ef5c90eSJian Yang setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING, 268*5ef5c90eSJian Yang &o.so_timestamping, sizeof(o.so_timestamping)) < 0) 269*5ef5c90eSJian Yang error(1, errno, "Failed to set SO_TIMESTAMPING"); 270*5ef5c90eSJian Yang } 271*5ef5c90eSJian Yang 272*5ef5c90eSJian Yang bool run_test_case(struct socket_type s, struct test_case t) 273*5ef5c90eSJian Yang { 274*5ef5c90eSJian Yang int port = (s.type == SOCK_RAW) ? 0 : next_port++; 275*5ef5c90eSJian Yang int read_size = op_size; 276*5ef5c90eSJian Yang struct sockaddr_in addr; 277*5ef5c90eSJian Yang bool failed = false; 278*5ef5c90eSJian Yang int src, dst, rcv; 279*5ef5c90eSJian Yang 280*5ef5c90eSJian Yang src = socket(AF_INET, s.type, s.protocol); 281*5ef5c90eSJian Yang if (src < 0) 282*5ef5c90eSJian Yang error(1, errno, "Failed to open src socket"); 283*5ef5c90eSJian Yang 284*5ef5c90eSJian Yang dst = socket(AF_INET, s.type, s.protocol); 285*5ef5c90eSJian Yang if (dst < 0) 286*5ef5c90eSJian Yang error(1, errno, "Failed to open dst socket"); 287*5ef5c90eSJian Yang 288*5ef5c90eSJian Yang memset(&addr, 0, sizeof(addr)); 289*5ef5c90eSJian Yang addr.sin_family = AF_INET; 290*5ef5c90eSJian Yang addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 291*5ef5c90eSJian Yang addr.sin_port = htons(port); 292*5ef5c90eSJian Yang 293*5ef5c90eSJian Yang if (bind(dst, (struct sockaddr *)&addr, sizeof(addr)) < 0) 294*5ef5c90eSJian Yang error(1, errno, "Failed to bind to port %d", port); 295*5ef5c90eSJian Yang 296*5ef5c90eSJian Yang if (s.type == SOCK_STREAM && (listen(dst, 1) < 0)) 297*5ef5c90eSJian Yang error(1, errno, "Failed to listen"); 298*5ef5c90eSJian Yang 299*5ef5c90eSJian Yang if (connect(src, (struct sockaddr *)&addr, sizeof(addr)) < 0) 300*5ef5c90eSJian Yang error(1, errno, "Failed to connect"); 301*5ef5c90eSJian Yang 302*5ef5c90eSJian Yang if (s.type == SOCK_STREAM) { 303*5ef5c90eSJian Yang rcv = accept(dst, NULL, NULL); 304*5ef5c90eSJian Yang if (rcv < 0) 305*5ef5c90eSJian Yang error(1, errno, "Failed to accept"); 306*5ef5c90eSJian Yang close(dst); 307*5ef5c90eSJian Yang } else { 308*5ef5c90eSJian Yang rcv = dst; 309*5ef5c90eSJian Yang } 310*5ef5c90eSJian Yang 311*5ef5c90eSJian Yang config_so_flags(rcv, t.sockopt); 312*5ef5c90eSJian Yang usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */ 313*5ef5c90eSJian Yang do_send(src); 314*5ef5c90eSJian Yang 315*5ef5c90eSJian Yang if (s.type == SOCK_RAW) 316*5ef5c90eSJian Yang read_size += 20; /* for IP header */ 317*5ef5c90eSJian Yang failed = do_recv(rcv, read_size, t.expected); 318*5ef5c90eSJian Yang 319*5ef5c90eSJian Yang close(rcv); 320*5ef5c90eSJian Yang close(src); 321*5ef5c90eSJian Yang 322*5ef5c90eSJian Yang return failed; 323*5ef5c90eSJian Yang } 324*5ef5c90eSJian Yang 325*5ef5c90eSJian Yang int main(int argc, char **argv) 326*5ef5c90eSJian Yang { 327*5ef5c90eSJian Yang bool all_protocols = true; 328*5ef5c90eSJian Yang bool all_tests = true; 329*5ef5c90eSJian Yang int arg_index = 0; 330*5ef5c90eSJian Yang int failures = 0; 331*5ef5c90eSJian Yang int s, t; 332*5ef5c90eSJian Yang char opt; 333*5ef5c90eSJian Yang 334*5ef5c90eSJian Yang while ((opt = getopt_long(argc, argv, "", long_options, 335*5ef5c90eSJian Yang &arg_index)) != -1) { 336*5ef5c90eSJian Yang switch (opt) { 337*5ef5c90eSJian Yang case 'l': 338*5ef5c90eSJian Yang for (t = 0; t < ARRAY_SIZE(test_cases); t++) { 339*5ef5c90eSJian Yang printf("%d\t", t); 340*5ef5c90eSJian Yang print_test_case(&test_cases[t]); 341*5ef5c90eSJian Yang } 342*5ef5c90eSJian Yang return 0; 343*5ef5c90eSJian Yang case 'n': 344*5ef5c90eSJian Yang t = atoi(optarg); 345*5ef5c90eSJian Yang if (t >= ARRAY_SIZE(test_cases)) 346*5ef5c90eSJian Yang error(1, 0, "Invalid test case: %d", t); 347*5ef5c90eSJian Yang all_tests = false; 348*5ef5c90eSJian Yang test_cases[t].enabled = true; 349*5ef5c90eSJian Yang break; 350*5ef5c90eSJian Yang case 's': 351*5ef5c90eSJian Yang op_size = atoi(optarg); 352*5ef5c90eSJian Yang break; 353*5ef5c90eSJian Yang case 't': 354*5ef5c90eSJian Yang all_protocols = false; 355*5ef5c90eSJian Yang socket_types[2].enabled = true; 356*5ef5c90eSJian Yang break; 357*5ef5c90eSJian Yang case 'u': 358*5ef5c90eSJian Yang all_protocols = false; 359*5ef5c90eSJian Yang socket_types[1].enabled = true; 360*5ef5c90eSJian Yang break; 361*5ef5c90eSJian Yang case 'i': 362*5ef5c90eSJian Yang all_protocols = false; 363*5ef5c90eSJian Yang socket_types[0].enabled = true; 364*5ef5c90eSJian Yang break; 365*5ef5c90eSJian Yang default: 366*5ef5c90eSJian Yang error(1, 0, "Failed to parse parameters."); 367*5ef5c90eSJian Yang } 368*5ef5c90eSJian Yang } 369*5ef5c90eSJian Yang 370*5ef5c90eSJian Yang for (s = 0; s < ARRAY_SIZE(socket_types); s++) { 371*5ef5c90eSJian Yang if (!all_protocols && !socket_types[s].enabled) 372*5ef5c90eSJian Yang continue; 373*5ef5c90eSJian Yang 374*5ef5c90eSJian Yang printf("Testing %s...\n", socket_types[s].friendly_name); 375*5ef5c90eSJian Yang for (t = 0; t < ARRAY_SIZE(test_cases); t++) { 376*5ef5c90eSJian Yang if (!all_tests && !test_cases[t].enabled) 377*5ef5c90eSJian Yang continue; 378*5ef5c90eSJian Yang 379*5ef5c90eSJian Yang printf("Starting testcase %d...\n", t); 380*5ef5c90eSJian Yang if (run_test_case(socket_types[s], test_cases[t])) { 381*5ef5c90eSJian Yang failures++; 382*5ef5c90eSJian Yang printf("FAILURE in test case "); 383*5ef5c90eSJian Yang print_test_case(&test_cases[t]); 384*5ef5c90eSJian Yang } 385*5ef5c90eSJian Yang } 386*5ef5c90eSJian Yang } 387*5ef5c90eSJian Yang if (!failures) 388*5ef5c90eSJian Yang printf("PASSED.\n"); 389*5ef5c90eSJian Yang return failures; 390*5ef5c90eSJian Yang } 391