15ef5c90eSJian Yang #include <errno.h> 25ef5c90eSJian Yang #include <error.h> 35ef5c90eSJian Yang #include <getopt.h> 45ef5c90eSJian Yang #include <stdbool.h> 55ef5c90eSJian Yang #include <stdio.h> 65ef5c90eSJian Yang #include <stdlib.h> 75ef5c90eSJian Yang #include <string.h> 85ef5c90eSJian Yang #include <unistd.h> 95ef5c90eSJian Yang 105ef5c90eSJian Yang #include <sys/time.h> 115ef5c90eSJian Yang #include <sys/socket.h> 125ef5c90eSJian Yang #include <sys/select.h> 135ef5c90eSJian Yang #include <sys/ioctl.h> 145ef5c90eSJian Yang #include <arpa/inet.h> 155ef5c90eSJian Yang #include <net/if.h> 165ef5c90eSJian Yang 175ef5c90eSJian Yang #include <asm/types.h> 185ef5c90eSJian Yang #include <linux/net_tstamp.h> 195ef5c90eSJian Yang #include <linux/errqueue.h> 205ef5c90eSJian Yang 215ef5c90eSJian Yang #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 225ef5c90eSJian Yang 235ef5c90eSJian Yang struct options { 245ef5c90eSJian Yang int so_timestamp; 255ef5c90eSJian Yang int so_timestampns; 265ef5c90eSJian Yang int so_timestamping; 275ef5c90eSJian Yang }; 285ef5c90eSJian Yang 295ef5c90eSJian Yang struct tstamps { 305ef5c90eSJian Yang bool tstamp; 315ef5c90eSJian Yang bool tstampns; 325ef5c90eSJian Yang bool swtstamp; 335ef5c90eSJian Yang bool hwtstamp; 345ef5c90eSJian Yang }; 355ef5c90eSJian Yang 365ef5c90eSJian Yang struct socket_type { 375ef5c90eSJian Yang char *friendly_name; 385ef5c90eSJian Yang int type; 395ef5c90eSJian Yang int protocol; 405ef5c90eSJian Yang bool enabled; 415ef5c90eSJian Yang }; 425ef5c90eSJian Yang 435ef5c90eSJian Yang struct test_case { 445ef5c90eSJian Yang struct options sockopt; 455ef5c90eSJian Yang struct tstamps expected; 465ef5c90eSJian Yang bool enabled; 47*0558c396Stannerlove bool warn_on_fail; 485ef5c90eSJian Yang }; 495ef5c90eSJian Yang 505ef5c90eSJian Yang struct sof_flag { 515ef5c90eSJian Yang int mask; 525ef5c90eSJian Yang char *name; 535ef5c90eSJian Yang }; 545ef5c90eSJian Yang 555ef5c90eSJian Yang static struct sof_flag sof_flags[] = { 565ef5c90eSJian Yang #define SOF_FLAG(f) { f, #f } 575ef5c90eSJian Yang SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE), 585ef5c90eSJian Yang SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE), 595ef5c90eSJian Yang SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE), 605ef5c90eSJian Yang }; 615ef5c90eSJian Yang 625ef5c90eSJian Yang static struct socket_type socket_types[] = { 635ef5c90eSJian Yang { "ip", SOCK_RAW, IPPROTO_EGP }, 645ef5c90eSJian Yang { "udp", SOCK_DGRAM, IPPROTO_UDP }, 655ef5c90eSJian Yang { "tcp", SOCK_STREAM, IPPROTO_TCP }, 665ef5c90eSJian Yang }; 675ef5c90eSJian Yang 685ef5c90eSJian Yang static struct test_case test_cases[] = { 695ef5c90eSJian Yang { {}, {} }, 705ef5c90eSJian Yang { 715ef5c90eSJian Yang { so_timestamp: 1 }, 725ef5c90eSJian Yang { tstamp: true } 735ef5c90eSJian Yang }, 745ef5c90eSJian Yang { 755ef5c90eSJian Yang { so_timestampns: 1 }, 765ef5c90eSJian Yang { tstampns: true } 775ef5c90eSJian Yang }, 785ef5c90eSJian Yang { 795ef5c90eSJian Yang { so_timestamp: 1, so_timestampns: 1 }, 805ef5c90eSJian Yang { tstampns: true } 815ef5c90eSJian Yang }, 825ef5c90eSJian Yang { 835ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE }, 845ef5c90eSJian Yang {} 855ef5c90eSJian Yang }, 865ef5c90eSJian Yang { 875ef5c90eSJian Yang /* Loopback device does not support hw timestamps. */ 885ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_RX_HARDWARE }, 895ef5c90eSJian Yang {} 905ef5c90eSJian Yang }, 915ef5c90eSJian Yang { 925ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_SOFTWARE }, 93*0558c396Stannerlove warn_on_fail : true 945ef5c90eSJian Yang }, 955ef5c90eSJian Yang { 965ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE 975ef5c90eSJian Yang | SOF_TIMESTAMPING_RX_HARDWARE }, 985ef5c90eSJian Yang {} 995ef5c90eSJian Yang }, 1005ef5c90eSJian Yang { 1015ef5c90eSJian Yang { so_timestamping: SOF_TIMESTAMPING_SOFTWARE 1025ef5c90eSJian Yang | SOF_TIMESTAMPING_RX_SOFTWARE }, 1035ef5c90eSJian Yang { swtstamp: true } 1045ef5c90eSJian Yang }, 1055ef5c90eSJian Yang { 1065ef5c90eSJian Yang { so_timestamp: 1, so_timestamping: SOF_TIMESTAMPING_SOFTWARE 1075ef5c90eSJian Yang | SOF_TIMESTAMPING_RX_SOFTWARE }, 1085ef5c90eSJian Yang { tstamp: true, swtstamp: true } 1095ef5c90eSJian Yang }, 1105ef5c90eSJian Yang }; 1115ef5c90eSJian Yang 1125ef5c90eSJian Yang static struct option long_options[] = { 1135ef5c90eSJian Yang { "list_tests", no_argument, 0, 'l' }, 1145ef5c90eSJian Yang { "test_num", required_argument, 0, 'n' }, 1155ef5c90eSJian Yang { "op_size", required_argument, 0, 's' }, 1165ef5c90eSJian Yang { "tcp", no_argument, 0, 't' }, 1175ef5c90eSJian Yang { "udp", no_argument, 0, 'u' }, 1185ef5c90eSJian Yang { "ip", no_argument, 0, 'i' }, 119*0558c396Stannerlove { "strict", no_argument, 0, 'S' }, 120865a6cbbStannerlove { NULL, 0, NULL, 0 }, 1215ef5c90eSJian Yang }; 1225ef5c90eSJian Yang 1235ef5c90eSJian Yang static int next_port = 19999; 1245ef5c90eSJian Yang static int op_size = 10 * 1024; 1255ef5c90eSJian Yang 1265ef5c90eSJian Yang void print_test_case(struct test_case *t) 1275ef5c90eSJian Yang { 1285ef5c90eSJian Yang int f = 0; 1295ef5c90eSJian Yang 1305ef5c90eSJian Yang printf("sockopts {"); 1315ef5c90eSJian Yang if (t->sockopt.so_timestamp) 1325ef5c90eSJian Yang printf(" SO_TIMESTAMP "); 1335ef5c90eSJian Yang if (t->sockopt.so_timestampns) 1345ef5c90eSJian Yang printf(" SO_TIMESTAMPNS "); 1355ef5c90eSJian Yang if (t->sockopt.so_timestamping) { 1365ef5c90eSJian Yang printf(" SO_TIMESTAMPING: {"); 1375ef5c90eSJian Yang for (f = 0; f < ARRAY_SIZE(sof_flags); f++) 1385ef5c90eSJian Yang if (t->sockopt.so_timestamping & sof_flags[f].mask) 1395ef5c90eSJian Yang printf(" %s |", sof_flags[f].name); 1405ef5c90eSJian Yang printf("}"); 1415ef5c90eSJian Yang } 1425ef5c90eSJian Yang printf("} expected cmsgs: {"); 1435ef5c90eSJian Yang if (t->expected.tstamp) 1445ef5c90eSJian Yang printf(" SCM_TIMESTAMP "); 1455ef5c90eSJian Yang if (t->expected.tstampns) 1465ef5c90eSJian Yang printf(" SCM_TIMESTAMPNS "); 1475ef5c90eSJian Yang if (t->expected.swtstamp || t->expected.hwtstamp) { 1485ef5c90eSJian Yang printf(" SCM_TIMESTAMPING {"); 1495ef5c90eSJian Yang if (t->expected.swtstamp) 1505ef5c90eSJian Yang printf("0"); 1515ef5c90eSJian Yang if (t->expected.swtstamp && t->expected.hwtstamp) 1525ef5c90eSJian Yang printf(","); 1535ef5c90eSJian Yang if (t->expected.hwtstamp) 1545ef5c90eSJian Yang printf("2"); 1555ef5c90eSJian Yang printf("}"); 1565ef5c90eSJian Yang } 1575ef5c90eSJian Yang printf("}\n"); 1585ef5c90eSJian Yang } 1595ef5c90eSJian Yang 1605ef5c90eSJian Yang void do_send(int src) 1615ef5c90eSJian Yang { 1625ef5c90eSJian Yang int r; 1635ef5c90eSJian Yang char *buf = malloc(op_size); 1645ef5c90eSJian Yang 1655ef5c90eSJian Yang memset(buf, 'z', op_size); 1665ef5c90eSJian Yang r = write(src, buf, op_size); 1675ef5c90eSJian Yang if (r < 0) 1685ef5c90eSJian Yang error(1, errno, "Failed to sendmsg"); 1695ef5c90eSJian Yang 1705ef5c90eSJian Yang free(buf); 1715ef5c90eSJian Yang } 1725ef5c90eSJian Yang 1735ef5c90eSJian Yang bool do_recv(int rcv, int read_size, struct tstamps expected) 1745ef5c90eSJian Yang { 1755ef5c90eSJian Yang const int CMSG_SIZE = 1024; 1765ef5c90eSJian Yang 1775ef5c90eSJian Yang struct scm_timestamping *ts; 1785ef5c90eSJian Yang struct tstamps actual = {}; 1795ef5c90eSJian Yang char cmsg_buf[CMSG_SIZE]; 1805ef5c90eSJian Yang struct iovec recv_iov; 1815ef5c90eSJian Yang struct cmsghdr *cmsg; 1825ef5c90eSJian Yang bool failed = false; 1835ef5c90eSJian Yang struct msghdr hdr; 1845ef5c90eSJian Yang int flags = 0; 1855ef5c90eSJian Yang int r; 1865ef5c90eSJian Yang 1875ef5c90eSJian Yang memset(&hdr, 0, sizeof(hdr)); 1885ef5c90eSJian Yang hdr.msg_iov = &recv_iov; 1895ef5c90eSJian Yang hdr.msg_iovlen = 1; 1905ef5c90eSJian Yang recv_iov.iov_base = malloc(read_size); 1915ef5c90eSJian Yang recv_iov.iov_len = read_size; 1925ef5c90eSJian Yang 1935ef5c90eSJian Yang hdr.msg_control = cmsg_buf; 1945ef5c90eSJian Yang hdr.msg_controllen = sizeof(cmsg_buf); 1955ef5c90eSJian Yang 1965ef5c90eSJian Yang r = recvmsg(rcv, &hdr, flags); 1975ef5c90eSJian Yang if (r < 0) 1985ef5c90eSJian Yang error(1, errno, "Failed to recvmsg"); 1995ef5c90eSJian Yang if (r != read_size) 2005ef5c90eSJian Yang error(1, 0, "Only received %d bytes of payload.", r); 2015ef5c90eSJian Yang 2025ef5c90eSJian Yang if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) 2035ef5c90eSJian Yang error(1, 0, "Message was truncated."); 2045ef5c90eSJian Yang 2055ef5c90eSJian Yang for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; 2065ef5c90eSJian Yang cmsg = CMSG_NXTHDR(&hdr, cmsg)) { 2075ef5c90eSJian Yang if (cmsg->cmsg_level != SOL_SOCKET) 2085ef5c90eSJian Yang error(1, 0, "Unexpected cmsg_level %d", 2095ef5c90eSJian Yang cmsg->cmsg_level); 2105ef5c90eSJian Yang switch (cmsg->cmsg_type) { 2115ef5c90eSJian Yang case SCM_TIMESTAMP: 2125ef5c90eSJian Yang actual.tstamp = true; 2135ef5c90eSJian Yang break; 2145ef5c90eSJian Yang case SCM_TIMESTAMPNS: 2155ef5c90eSJian Yang actual.tstampns = true; 2165ef5c90eSJian Yang break; 2175ef5c90eSJian Yang case SCM_TIMESTAMPING: 2185ef5c90eSJian Yang ts = (struct scm_timestamping *)CMSG_DATA(cmsg); 2195ef5c90eSJian Yang actual.swtstamp = !!ts->ts[0].tv_sec; 2205ef5c90eSJian Yang if (ts->ts[1].tv_sec != 0) 2215ef5c90eSJian Yang error(0, 0, "ts[1] should not be set."); 2225ef5c90eSJian Yang actual.hwtstamp = !!ts->ts[2].tv_sec; 2235ef5c90eSJian Yang break; 2245ef5c90eSJian Yang default: 2255ef5c90eSJian Yang error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type); 2265ef5c90eSJian Yang } 2275ef5c90eSJian Yang } 2285ef5c90eSJian Yang 2295ef5c90eSJian Yang #define VALIDATE(field) \ 2305ef5c90eSJian Yang do { \ 2315ef5c90eSJian Yang if (expected.field != actual.field) { \ 2325ef5c90eSJian Yang if (expected.field) \ 2335ef5c90eSJian Yang error(0, 0, "Expected " #field " to be set."); \ 2345ef5c90eSJian Yang else \ 2355ef5c90eSJian Yang error(0, 0, \ 2365ef5c90eSJian Yang "Expected " #field " to not be set."); \ 2375ef5c90eSJian Yang failed = true; \ 2385ef5c90eSJian Yang } \ 2395ef5c90eSJian Yang } while (0) 2405ef5c90eSJian Yang 2415ef5c90eSJian Yang VALIDATE(tstamp); 2425ef5c90eSJian Yang VALIDATE(tstampns); 2435ef5c90eSJian Yang VALIDATE(swtstamp); 2445ef5c90eSJian Yang VALIDATE(hwtstamp); 2455ef5c90eSJian Yang #undef VALIDATE 2465ef5c90eSJian Yang 2475ef5c90eSJian Yang free(recv_iov.iov_base); 2485ef5c90eSJian Yang 2495ef5c90eSJian Yang return failed; 2505ef5c90eSJian Yang } 2515ef5c90eSJian Yang 2525ef5c90eSJian Yang void config_so_flags(int rcv, struct options o) 2535ef5c90eSJian Yang { 2545ef5c90eSJian Yang int on = 1; 2555ef5c90eSJian Yang 2565ef5c90eSJian Yang if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 2575ef5c90eSJian Yang error(1, errno, "Failed to enable SO_REUSEADDR"); 2585ef5c90eSJian Yang 2595ef5c90eSJian Yang if (o.so_timestamp && 2605ef5c90eSJian Yang setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP, 2615ef5c90eSJian Yang &o.so_timestamp, sizeof(o.so_timestamp)) < 0) 2625ef5c90eSJian Yang error(1, errno, "Failed to enable SO_TIMESTAMP"); 2635ef5c90eSJian Yang 2645ef5c90eSJian Yang if (o.so_timestampns && 2655ef5c90eSJian Yang setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS, 2665ef5c90eSJian Yang &o.so_timestampns, sizeof(o.so_timestampns)) < 0) 2675ef5c90eSJian Yang error(1, errno, "Failed to enable SO_TIMESTAMPNS"); 2685ef5c90eSJian Yang 2695ef5c90eSJian Yang if (o.so_timestamping && 2705ef5c90eSJian Yang setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING, 2715ef5c90eSJian Yang &o.so_timestamping, sizeof(o.so_timestamping)) < 0) 2725ef5c90eSJian Yang error(1, errno, "Failed to set SO_TIMESTAMPING"); 2735ef5c90eSJian Yang } 2745ef5c90eSJian Yang 2755ef5c90eSJian Yang bool run_test_case(struct socket_type s, struct test_case t) 2765ef5c90eSJian Yang { 2775ef5c90eSJian Yang int port = (s.type == SOCK_RAW) ? 0 : next_port++; 2785ef5c90eSJian Yang int read_size = op_size; 2795ef5c90eSJian Yang struct sockaddr_in addr; 2805ef5c90eSJian Yang bool failed = false; 2815ef5c90eSJian Yang int src, dst, rcv; 2825ef5c90eSJian Yang 2835ef5c90eSJian Yang src = socket(AF_INET, s.type, s.protocol); 2845ef5c90eSJian Yang if (src < 0) 2855ef5c90eSJian Yang error(1, errno, "Failed to open src socket"); 2865ef5c90eSJian Yang 2875ef5c90eSJian Yang dst = socket(AF_INET, s.type, s.protocol); 2885ef5c90eSJian Yang if (dst < 0) 2895ef5c90eSJian Yang error(1, errno, "Failed to open dst socket"); 2905ef5c90eSJian Yang 2915ef5c90eSJian Yang memset(&addr, 0, sizeof(addr)); 2925ef5c90eSJian Yang addr.sin_family = AF_INET; 2935ef5c90eSJian Yang addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2945ef5c90eSJian Yang addr.sin_port = htons(port); 2955ef5c90eSJian Yang 2965ef5c90eSJian Yang if (bind(dst, (struct sockaddr *)&addr, sizeof(addr)) < 0) 2975ef5c90eSJian Yang error(1, errno, "Failed to bind to port %d", port); 2985ef5c90eSJian Yang 2995ef5c90eSJian Yang if (s.type == SOCK_STREAM && (listen(dst, 1) < 0)) 3005ef5c90eSJian Yang error(1, errno, "Failed to listen"); 3015ef5c90eSJian Yang 3025ef5c90eSJian Yang if (connect(src, (struct sockaddr *)&addr, sizeof(addr)) < 0) 3035ef5c90eSJian Yang error(1, errno, "Failed to connect"); 3045ef5c90eSJian Yang 3055ef5c90eSJian Yang if (s.type == SOCK_STREAM) { 3065ef5c90eSJian Yang rcv = accept(dst, NULL, NULL); 3075ef5c90eSJian Yang if (rcv < 0) 3085ef5c90eSJian Yang error(1, errno, "Failed to accept"); 3095ef5c90eSJian Yang close(dst); 3105ef5c90eSJian Yang } else { 3115ef5c90eSJian Yang rcv = dst; 3125ef5c90eSJian Yang } 3135ef5c90eSJian Yang 3145ef5c90eSJian Yang config_so_flags(rcv, t.sockopt); 3155ef5c90eSJian Yang usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */ 3165ef5c90eSJian Yang do_send(src); 3175ef5c90eSJian Yang 3185ef5c90eSJian Yang if (s.type == SOCK_RAW) 3195ef5c90eSJian Yang read_size += 20; /* for IP header */ 3205ef5c90eSJian Yang failed = do_recv(rcv, read_size, t.expected); 3215ef5c90eSJian Yang 3225ef5c90eSJian Yang close(rcv); 3235ef5c90eSJian Yang close(src); 3245ef5c90eSJian Yang 3255ef5c90eSJian Yang return failed; 3265ef5c90eSJian Yang } 3275ef5c90eSJian Yang 3285ef5c90eSJian Yang int main(int argc, char **argv) 3295ef5c90eSJian Yang { 3305ef5c90eSJian Yang bool all_protocols = true; 3315ef5c90eSJian Yang bool all_tests = true; 332*0558c396Stannerlove bool strict = false; 3335ef5c90eSJian Yang int arg_index = 0; 3345ef5c90eSJian Yang int failures = 0; 3355ef5c90eSJian Yang int s, t; 3365ef5c90eSJian Yang char opt; 3375ef5c90eSJian Yang 3385ef5c90eSJian Yang while ((opt = getopt_long(argc, argv, "", long_options, 3395ef5c90eSJian Yang &arg_index)) != -1) { 3405ef5c90eSJian Yang switch (opt) { 3415ef5c90eSJian Yang case 'l': 3425ef5c90eSJian Yang for (t = 0; t < ARRAY_SIZE(test_cases); t++) { 3435ef5c90eSJian Yang printf("%d\t", t); 3445ef5c90eSJian Yang print_test_case(&test_cases[t]); 3455ef5c90eSJian Yang } 3465ef5c90eSJian Yang return 0; 3475ef5c90eSJian Yang case 'n': 3485ef5c90eSJian Yang t = atoi(optarg); 3495ef5c90eSJian Yang if (t >= ARRAY_SIZE(test_cases)) 3505ef5c90eSJian Yang error(1, 0, "Invalid test case: %d", t); 3515ef5c90eSJian Yang all_tests = false; 3525ef5c90eSJian Yang test_cases[t].enabled = true; 3535ef5c90eSJian Yang break; 3545ef5c90eSJian Yang case 's': 3555ef5c90eSJian Yang op_size = atoi(optarg); 3565ef5c90eSJian Yang break; 3575ef5c90eSJian Yang case 't': 3585ef5c90eSJian Yang all_protocols = false; 3595ef5c90eSJian Yang socket_types[2].enabled = true; 3605ef5c90eSJian Yang break; 3615ef5c90eSJian Yang case 'u': 3625ef5c90eSJian Yang all_protocols = false; 3635ef5c90eSJian Yang socket_types[1].enabled = true; 3645ef5c90eSJian Yang break; 3655ef5c90eSJian Yang case 'i': 3665ef5c90eSJian Yang all_protocols = false; 3675ef5c90eSJian Yang socket_types[0].enabled = true; 3685ef5c90eSJian Yang break; 369*0558c396Stannerlove case 'S': 370*0558c396Stannerlove strict = true; 371*0558c396Stannerlove break; 3725ef5c90eSJian Yang default: 3735ef5c90eSJian Yang error(1, 0, "Failed to parse parameters."); 3745ef5c90eSJian Yang } 3755ef5c90eSJian Yang } 3765ef5c90eSJian Yang 3775ef5c90eSJian Yang for (s = 0; s < ARRAY_SIZE(socket_types); s++) { 3785ef5c90eSJian Yang if (!all_protocols && !socket_types[s].enabled) 3795ef5c90eSJian Yang continue; 3805ef5c90eSJian Yang 3815ef5c90eSJian Yang printf("Testing %s...\n", socket_types[s].friendly_name); 3825ef5c90eSJian Yang for (t = 0; t < ARRAY_SIZE(test_cases); t++) { 3835ef5c90eSJian Yang if (!all_tests && !test_cases[t].enabled) 3845ef5c90eSJian Yang continue; 3855ef5c90eSJian Yang 3865ef5c90eSJian Yang printf("Starting testcase %d...\n", t); 3875ef5c90eSJian Yang if (run_test_case(socket_types[s], test_cases[t])) { 388*0558c396Stannerlove if (strict || !test_cases[t].warn_on_fail) 3895ef5c90eSJian Yang failures++; 3905ef5c90eSJian Yang printf("FAILURE in test case "); 3915ef5c90eSJian Yang print_test_case(&test_cases[t]); 3925ef5c90eSJian Yang } 3935ef5c90eSJian Yang } 3945ef5c90eSJian Yang } 3955ef5c90eSJian Yang if (!failures) 3965ef5c90eSJian Yang printf("PASSED.\n"); 3975ef5c90eSJian Yang return failures; 3985ef5c90eSJian Yang } 399