11 #include <sys/socket.h>
12 #include <sys/select.h>
13 #include <sys/ioctl.h>
14 #include <arpa/inet.h>
17 #include <asm/types.h>
18 #include <linux/net_tstamp.h>
19 #include <linux/errqueue.h>
21 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
44 struct options sockopt;
45 struct tstamps expected;
55 static struct sof_flag sof_flags[] = {
56 #define SOF_FLAG(f) { f, #f }
57 SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE),
58 SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE),
59 SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE),
62 static struct socket_type socket_types[] = {
63 { "ip", SOCK_RAW, IPPROTO_EGP },
64 { "udp", SOCK_DGRAM, IPPROTO_UDP },
65 { "tcp", SOCK_STREAM, IPPROTO_TCP },
68 static struct test_case test_cases[] = {
71 { .so_timestamp = 1 },
75 { .so_timestampns = 1 },
79 { .so_timestamp = 1, .so_timestampns = 1 },
83 { .so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE },
87 /* Loopback device does not support hw timestamps. */
88 { .so_timestamping = SOF_TIMESTAMPING_RX_HARDWARE },
92 { .so_timestamping = SOF_TIMESTAMPING_SOFTWARE },
96 { .so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE
97 | SOF_TIMESTAMPING_RX_HARDWARE },
101 { .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
102 | SOF_TIMESTAMPING_RX_SOFTWARE },
106 { .so_timestamp = 1, .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
107 | SOF_TIMESTAMPING_RX_SOFTWARE },
108 { .tstamp = true, .swtstamp = true }
112 static struct option long_options[] = {
113 { "list_tests", no_argument, 0, 'l' },
114 { "test_num", required_argument, 0, 'n' },
115 { "op_size", required_argument, 0, 's' },
116 { "tcp", no_argument, 0, 't' },
117 { "udp", no_argument, 0, 'u' },
118 { "ip", no_argument, 0, 'i' },
119 { "strict", no_argument, 0, 'S' },
120 { "ipv4", no_argument, 0, '4' },
121 { "ipv6", no_argument, 0, '6' },
122 { NULL, 0, NULL, 0 },
125 static int next_port = 19999;
126 static int op_size = 10 * 1024;
128 void print_test_case(struct test_case *t)
132 printf("sockopts {");
133 if (t->sockopt.so_timestamp)
134 printf(" SO_TIMESTAMP ");
135 if (t->sockopt.so_timestampns)
136 printf(" SO_TIMESTAMPNS ");
137 if (t->sockopt.so_timestamping) {
138 printf(" SO_TIMESTAMPING: {");
139 for (f = 0; f < ARRAY_SIZE(sof_flags); f++)
140 if (t->sockopt.so_timestamping & sof_flags[f].mask)
141 printf(" %s |", sof_flags[f].name);
144 printf("} expected cmsgs: {");
145 if (t->expected.tstamp)
146 printf(" SCM_TIMESTAMP ");
147 if (t->expected.tstampns)
148 printf(" SCM_TIMESTAMPNS ");
149 if (t->expected.swtstamp || t->expected.hwtstamp) {
150 printf(" SCM_TIMESTAMPING {");
151 if (t->expected.swtstamp)
153 if (t->expected.swtstamp && t->expected.hwtstamp)
155 if (t->expected.hwtstamp)
162 void do_send(int src)
165 char *buf = malloc(op_size);
167 memset(buf, 'z', op_size);
168 r = write(src, buf, op_size);
170 error(1, errno, "Failed to sendmsg");
175 bool do_recv(int rcv, int read_size, struct tstamps expected)
177 const int CMSG_SIZE = 1024;
179 struct scm_timestamping *ts;
180 struct tstamps actual = {};
181 char cmsg_buf[CMSG_SIZE];
182 struct iovec recv_iov;
183 struct cmsghdr *cmsg;
189 memset(&hdr, 0, sizeof(hdr));
190 hdr.msg_iov = &recv_iov;
192 recv_iov.iov_base = malloc(read_size);
193 recv_iov.iov_len = read_size;
195 hdr.msg_control = cmsg_buf;
196 hdr.msg_controllen = sizeof(cmsg_buf);
198 r = recvmsg(rcv, &hdr, flags);
200 error(1, errno, "Failed to recvmsg");
202 error(1, 0, "Only received %d bytes of payload.", r);
204 if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC))
205 error(1, 0, "Message was truncated.");
207 for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL;
208 cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
209 if (cmsg->cmsg_level != SOL_SOCKET)
210 error(1, 0, "Unexpected cmsg_level %d",
212 switch (cmsg->cmsg_type) {
214 actual.tstamp = true;
216 case SCM_TIMESTAMPNS:
217 actual.tstampns = true;
219 case SCM_TIMESTAMPING:
220 ts = (struct scm_timestamping *)CMSG_DATA(cmsg);
221 actual.swtstamp = !!ts->ts[0].tv_sec;
222 if (ts->ts[1].tv_sec != 0)
223 error(0, 0, "ts[1] should not be set.");
224 actual.hwtstamp = !!ts->ts[2].tv_sec;
227 error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type);
231 #define VALIDATE(field) \
233 if (expected.field != actual.field) { \
234 if (expected.field) \
235 error(0, 0, "Expected " #field " to be set."); \
238 "Expected " #field " to not be set."); \
249 free(recv_iov.iov_base);
254 void config_so_flags(int rcv, struct options o)
258 if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
259 error(1, errno, "Failed to enable SO_REUSEADDR");
261 if (o.so_timestamp &&
262 setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP,
263 &o.so_timestamp, sizeof(o.so_timestamp)) < 0)
264 error(1, errno, "Failed to enable SO_TIMESTAMP");
266 if (o.so_timestampns &&
267 setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS,
268 &o.so_timestampns, sizeof(o.so_timestampns)) < 0)
269 error(1, errno, "Failed to enable SO_TIMESTAMPNS");
271 if (o.so_timestamping &&
272 setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING,
273 &o.so_timestamping, sizeof(o.so_timestamping)) < 0)
274 error(1, errno, "Failed to set SO_TIMESTAMPING");
277 bool run_test_case(struct socket_type *s, int test_num, char ip_version,
281 struct sockaddr_in6 addr6;
282 struct sockaddr_in addr4;
283 struct sockaddr addr_un;
285 int read_size = op_size;
286 int src, dst, rcv, port;
290 port = (s->type == SOCK_RAW) ? 0 : next_port++;
291 memset(&addr, 0, sizeof(addr));
292 if (ip_version == '4') {
293 addr.addr4.sin_family = AF_INET;
294 addr.addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
295 addr.addr4.sin_port = htons(port);
296 addr_size = sizeof(addr.addr4);
297 if (s->type == SOCK_RAW)
298 read_size += 20; /* for IPv4 header */
300 addr.addr6.sin6_family = AF_INET6;
301 addr.addr6.sin6_addr = in6addr_loopback;
302 addr.addr6.sin6_port = htons(port);
303 addr_size = sizeof(addr.addr6);
305 printf("Starting testcase %d over ipv%c...\n", test_num, ip_version);
306 src = socket(addr.addr_un.sa_family, s->type,
309 error(1, errno, "Failed to open src socket");
311 dst = socket(addr.addr_un.sa_family, s->type,
314 error(1, errno, "Failed to open dst socket");
316 if (bind(dst, &addr.addr_un, addr_size) < 0)
317 error(1, errno, "Failed to bind to port %d", port);
319 if (s->type == SOCK_STREAM && (listen(dst, 1) < 0))
320 error(1, errno, "Failed to listen");
322 if (connect(src, &addr.addr_un, addr_size) < 0)
323 error(1, errno, "Failed to connect");
325 if (s->type == SOCK_STREAM) {
326 rcv = accept(dst, NULL, NULL);
328 error(1, errno, "Failed to accept");
334 config_so_flags(rcv, test_cases[test_num].sockopt);
335 usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */
338 failed = do_recv(rcv, read_size, test_cases[test_num].expected);
344 printf("FAILURE in testcase %d over ipv%c ", test_num,
346 print_test_case(&test_cases[test_num]);
347 if (!strict && test_cases[test_num].warn_on_fail)
353 int main(int argc, char **argv)
355 bool all_protocols = true;
356 bool all_tests = true;
357 bool cfg_ipv4 = false;
358 bool cfg_ipv6 = false;
365 while ((opt = getopt_long(argc, argv, "", long_options,
366 &arg_index)) != -1) {
369 for (t = 0; t < ARRAY_SIZE(test_cases); t++) {
371 print_test_case(&test_cases[t]);
376 if (t >= ARRAY_SIZE(test_cases))
377 error(1, 0, "Invalid test case: %d", t);
379 test_cases[t].enabled = true;
382 op_size = atoi(optarg);
385 all_protocols = false;
386 socket_types[2].enabled = true;
389 all_protocols = false;
390 socket_types[1].enabled = true;
393 all_protocols = false;
394 socket_types[0].enabled = true;
406 error(1, 0, "Failed to parse parameters.");
410 for (s = 0; s < ARRAY_SIZE(socket_types); s++) {
411 if (!all_protocols && !socket_types[s].enabled)
414 printf("Testing %s...\n", socket_types[s].friendly_name);
415 for (t = 0; t < ARRAY_SIZE(test_cases); t++) {
416 if (!all_tests && !test_cases[t].enabled)
418 if (cfg_ipv4 || !cfg_ipv6)
419 if (run_test_case(&socket_types[s], t, '4',
422 if (cfg_ipv6 || !cfg_ipv4)
423 if (run_test_case(&socket_types[s], t, '6',