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