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
;
54 static struct sof_flag sof_flags
[] = {
55 #define SOF_FLAG(f) { f, #f }
56 SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE
),
57 SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE
),
58 SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE
),
61 static struct socket_type socket_types
[] = {
62 { "ip", SOCK_RAW
, IPPROTO_EGP
},
63 { "udp", SOCK_DGRAM
, IPPROTO_UDP
},
64 { "tcp", SOCK_STREAM
, IPPROTO_TCP
},
67 static struct test_case test_cases
[] = {
74 { so_timestampns
: 1 },
78 { so_timestamp
: 1, so_timestampns
: 1 },
82 { so_timestamping
: SOF_TIMESTAMPING_RX_SOFTWARE
},
86 /* Loopback device does not support hw timestamps. */
87 { so_timestamping
: SOF_TIMESTAMPING_RX_HARDWARE
},
91 { so_timestamping
: SOF_TIMESTAMPING_SOFTWARE
},
95 { so_timestamping
: SOF_TIMESTAMPING_RX_SOFTWARE
96 | SOF_TIMESTAMPING_RX_HARDWARE
},
100 { so_timestamping
: SOF_TIMESTAMPING_SOFTWARE
101 | SOF_TIMESTAMPING_RX_SOFTWARE
},
105 { so_timestamp
: 1, so_timestamping
: SOF_TIMESTAMPING_SOFTWARE
106 | SOF_TIMESTAMPING_RX_SOFTWARE
},
107 { tstamp
: true, swtstamp
: true }
111 static struct option long_options
[] = {
112 { "list_tests", no_argument
, 0, 'l' },
113 { "test_num", required_argument
, 0, 'n' },
114 { "op_size", required_argument
, 0, 's' },
115 { "tcp", no_argument
, 0, 't' },
116 { "udp", no_argument
, 0, 'u' },
117 { "ip", no_argument
, 0, 'i' },
120 static int next_port
= 19999;
121 static int op_size
= 10 * 1024;
123 void print_test_case(struct test_case
*t
)
127 printf("sockopts {");
128 if (t
->sockopt
.so_timestamp
)
129 printf(" SO_TIMESTAMP ");
130 if (t
->sockopt
.so_timestampns
)
131 printf(" SO_TIMESTAMPNS ");
132 if (t
->sockopt
.so_timestamping
) {
133 printf(" SO_TIMESTAMPING: {");
134 for (f
= 0; f
< ARRAY_SIZE(sof_flags
); f
++)
135 if (t
->sockopt
.so_timestamping
& sof_flags
[f
].mask
)
136 printf(" %s |", sof_flags
[f
].name
);
139 printf("} expected cmsgs: {");
140 if (t
->expected
.tstamp
)
141 printf(" SCM_TIMESTAMP ");
142 if (t
->expected
.tstampns
)
143 printf(" SCM_TIMESTAMPNS ");
144 if (t
->expected
.swtstamp
|| t
->expected
.hwtstamp
) {
145 printf(" SCM_TIMESTAMPING {");
146 if (t
->expected
.swtstamp
)
148 if (t
->expected
.swtstamp
&& t
->expected
.hwtstamp
)
150 if (t
->expected
.hwtstamp
)
157 void do_send(int src
)
160 char *buf
= malloc(op_size
);
162 memset(buf
, 'z', op_size
);
163 r
= write(src
, buf
, op_size
);
165 error(1, errno
, "Failed to sendmsg");
170 bool do_recv(int rcv
, int read_size
, struct tstamps expected
)
172 const int CMSG_SIZE
= 1024;
174 struct scm_timestamping
*ts
;
175 struct tstamps actual
= {};
176 char cmsg_buf
[CMSG_SIZE
];
177 struct iovec recv_iov
;
178 struct cmsghdr
*cmsg
;
184 memset(&hdr
, 0, sizeof(hdr
));
185 hdr
.msg_iov
= &recv_iov
;
187 recv_iov
.iov_base
= malloc(read_size
);
188 recv_iov
.iov_len
= read_size
;
190 hdr
.msg_control
= cmsg_buf
;
191 hdr
.msg_controllen
= sizeof(cmsg_buf
);
193 r
= recvmsg(rcv
, &hdr
, flags
);
195 error(1, errno
, "Failed to recvmsg");
197 error(1, 0, "Only received %d bytes of payload.", r
);
199 if (hdr
.msg_flags
& (MSG_TRUNC
| MSG_CTRUNC
))
200 error(1, 0, "Message was truncated.");
202 for (cmsg
= CMSG_FIRSTHDR(&hdr
); cmsg
!= NULL
;
203 cmsg
= CMSG_NXTHDR(&hdr
, cmsg
)) {
204 if (cmsg
->cmsg_level
!= SOL_SOCKET
)
205 error(1, 0, "Unexpected cmsg_level %d",
207 switch (cmsg
->cmsg_type
) {
209 actual
.tstamp
= true;
211 case SCM_TIMESTAMPNS
:
212 actual
.tstampns
= true;
214 case SCM_TIMESTAMPING
:
215 ts
= (struct scm_timestamping
*)CMSG_DATA(cmsg
);
216 actual
.swtstamp
= !!ts
->ts
[0].tv_sec
;
217 if (ts
->ts
[1].tv_sec
!= 0)
218 error(0, 0, "ts[1] should not be set.");
219 actual
.hwtstamp
= !!ts
->ts
[2].tv_sec
;
222 error(1, 0, "Unexpected cmsg_type %d", cmsg
->cmsg_type
);
226 #define VALIDATE(field) \
228 if (expected.field != actual.field) { \
229 if (expected.field) \
230 error(0, 0, "Expected " #field " to be set."); \
233 "Expected " #field " to not be set."); \
244 free(recv_iov
.iov_base
);
249 void config_so_flags(int rcv
, struct options o
)
253 if (setsockopt(rcv
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) < 0)
254 error(1, errno
, "Failed to enable SO_REUSEADDR");
256 if (o
.so_timestamp
&&
257 setsockopt(rcv
, SOL_SOCKET
, SO_TIMESTAMP
,
258 &o
.so_timestamp
, sizeof(o
.so_timestamp
)) < 0)
259 error(1, errno
, "Failed to enable SO_TIMESTAMP");
261 if (o
.so_timestampns
&&
262 setsockopt(rcv
, SOL_SOCKET
, SO_TIMESTAMPNS
,
263 &o
.so_timestampns
, sizeof(o
.so_timestampns
)) < 0)
264 error(1, errno
, "Failed to enable SO_TIMESTAMPNS");
266 if (o
.so_timestamping
&&
267 setsockopt(rcv
, SOL_SOCKET
, SO_TIMESTAMPING
,
268 &o
.so_timestamping
, sizeof(o
.so_timestamping
)) < 0)
269 error(1, errno
, "Failed to set SO_TIMESTAMPING");
272 bool run_test_case(struct socket_type s
, struct test_case t
)
274 int port
= (s
.type
== SOCK_RAW
) ? 0 : next_port
++;
275 int read_size
= op_size
;
276 struct sockaddr_in addr
;
280 src
= socket(AF_INET
, s
.type
, s
.protocol
);
282 error(1, errno
, "Failed to open src socket");
284 dst
= socket(AF_INET
, s
.type
, s
.protocol
);
286 error(1, errno
, "Failed to open dst socket");
288 memset(&addr
, 0, sizeof(addr
));
289 addr
.sin_family
= AF_INET
;
290 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
291 addr
.sin_port
= htons(port
);
293 if (bind(dst
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
294 error(1, errno
, "Failed to bind to port %d", port
);
296 if (s
.type
== SOCK_STREAM
&& (listen(dst
, 1) < 0))
297 error(1, errno
, "Failed to listen");
299 if (connect(src
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
300 error(1, errno
, "Failed to connect");
302 if (s
.type
== SOCK_STREAM
) {
303 rcv
= accept(dst
, NULL
, NULL
);
305 error(1, errno
, "Failed to accept");
311 config_so_flags(rcv
, t
.sockopt
);
312 usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */
315 if (s
.type
== SOCK_RAW
)
316 read_size
+= 20; /* for IP header */
317 failed
= do_recv(rcv
, read_size
, t
.expected
);
325 int main(int argc
, char **argv
)
327 bool all_protocols
= true;
328 bool all_tests
= true;
334 while ((opt
= getopt_long(argc
, argv
, "", long_options
,
335 &arg_index
)) != -1) {
338 for (t
= 0; t
< ARRAY_SIZE(test_cases
); t
++) {
340 print_test_case(&test_cases
[t
]);
345 if (t
>= ARRAY_SIZE(test_cases
))
346 error(1, 0, "Invalid test case: %d", t
);
348 test_cases
[t
].enabled
= true;
351 op_size
= atoi(optarg
);
354 all_protocols
= false;
355 socket_types
[2].enabled
= true;
358 all_protocols
= false;
359 socket_types
[1].enabled
= true;
362 all_protocols
= false;
363 socket_types
[0].enabled
= true;
366 error(1, 0, "Failed to parse parameters.");
370 for (s
= 0; s
< ARRAY_SIZE(socket_types
); s
++) {
371 if (!all_protocols
&& !socket_types
[s
].enabled
)
374 printf("Testing %s...\n", socket_types
[s
].friendly_name
);
375 for (t
= 0; t
< ARRAY_SIZE(test_cases
); t
++) {
376 if (!all_tests
&& !test_cases
[t
].enabled
)
379 printf("Starting testcase %d...\n", t
);
380 if (run_test_case(socket_types
[s
], test_cases
[t
])) {
382 printf("FAILURE in test case ");
383 print_test_case(&test_cases
[t
]);