10 #include <sys/socket.h>
11 #include <sys/select.h>
12 #include <sys/ioctl.h>
13 #include <arpa/inet.h>
16 #include <asm/types.h>
17 #include <linux/net_tstamp.h>
18 #include <linux/errqueue.h>
20 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
43 struct options sockopt
;
44 struct tstamps expected
;
53 static struct sof_flag sof_flags
[] = {
54 #define SOF_FLAG(f) { f, #f }
55 SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE
),
56 SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE
),
57 SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE
),
60 static struct socket_type socket_types
[] = {
61 { "ip", SOCK_RAW
, IPPROTO_EGP
},
62 { "udp", SOCK_DGRAM
, IPPROTO_UDP
},
63 { "tcp", SOCK_STREAM
, IPPROTO_TCP
},
66 static struct test_case test_cases
[] = {
73 { so_timestampns
: 1 },
77 { so_timestamp
: 1, so_timestampns
: 1 },
81 { so_timestamping
: SOF_TIMESTAMPING_RX_SOFTWARE
},
85 /* Loopback device does not support hw timestamps. */
86 { so_timestamping
: SOF_TIMESTAMPING_RX_HARDWARE
},
90 { so_timestamping
: SOF_TIMESTAMPING_SOFTWARE
},
94 { so_timestamping
: SOF_TIMESTAMPING_RX_SOFTWARE
95 | SOF_TIMESTAMPING_RX_HARDWARE
},
99 { so_timestamping
: SOF_TIMESTAMPING_SOFTWARE
100 | SOF_TIMESTAMPING_RX_SOFTWARE
},
104 { so_timestamp
: 1, so_timestamping
: SOF_TIMESTAMPING_SOFTWARE
105 | SOF_TIMESTAMPING_RX_SOFTWARE
},
106 { tstamp
: true, swtstamp
: true }
110 static struct option long_options
[] = {
111 { "list_tests", no_argument
, 0, 'l' },
112 { "test_num", required_argument
, 0, 'n' },
113 { "op_size", required_argument
, 0, 's' },
114 { "tcp", no_argument
, 0, 't' },
115 { "udp", no_argument
, 0, 'u' },
116 { "ip", no_argument
, 0, 'i' },
119 static int next_port
= 19999;
120 static int op_size
= 10 * 1024;
122 void print_test_case(struct test_case
*t
)
126 printf("sockopts {");
127 if (t
->sockopt
.so_timestamp
)
128 printf(" SO_TIMESTAMP ");
129 if (t
->sockopt
.so_timestampns
)
130 printf(" SO_TIMESTAMPNS ");
131 if (t
->sockopt
.so_timestamping
) {
132 printf(" SO_TIMESTAMPING: {");
133 for (f
= 0; f
< ARRAY_SIZE(sof_flags
); f
++)
134 if (t
->sockopt
.so_timestamping
& sof_flags
[f
].mask
)
135 printf(" %s |", sof_flags
[f
].name
);
138 printf("} expected cmsgs: {");
139 if (t
->expected
.tstamp
)
140 printf(" SCM_TIMESTAMP ");
141 if (t
->expected
.tstampns
)
142 printf(" SCM_TIMESTAMPNS ");
143 if (t
->expected
.swtstamp
|| t
->expected
.hwtstamp
) {
144 printf(" SCM_TIMESTAMPING {");
145 if (t
->expected
.swtstamp
)
147 if (t
->expected
.swtstamp
&& t
->expected
.hwtstamp
)
149 if (t
->expected
.hwtstamp
)
156 void do_send(int src
)
159 char *buf
= malloc(op_size
);
161 memset(buf
, 'z', op_size
);
162 r
= write(src
, buf
, op_size
);
164 error(1, errno
, "Failed to sendmsg");
169 bool do_recv(int rcv
, int read_size
, struct tstamps expected
)
171 const int CMSG_SIZE
= 1024;
173 struct scm_timestamping
*ts
;
174 struct tstamps actual
= {};
175 char cmsg_buf
[CMSG_SIZE
];
176 struct iovec recv_iov
;
177 struct cmsghdr
*cmsg
;
183 memset(&hdr
, 0, sizeof(hdr
));
184 hdr
.msg_iov
= &recv_iov
;
186 recv_iov
.iov_base
= malloc(read_size
);
187 recv_iov
.iov_len
= read_size
;
189 hdr
.msg_control
= cmsg_buf
;
190 hdr
.msg_controllen
= sizeof(cmsg_buf
);
192 r
= recvmsg(rcv
, &hdr
, flags
);
194 error(1, errno
, "Failed to recvmsg");
196 error(1, 0, "Only received %d bytes of payload.", r
);
198 if (hdr
.msg_flags
& (MSG_TRUNC
| MSG_CTRUNC
))
199 error(1, 0, "Message was truncated.");
201 for (cmsg
= CMSG_FIRSTHDR(&hdr
); cmsg
!= NULL
;
202 cmsg
= CMSG_NXTHDR(&hdr
, cmsg
)) {
203 if (cmsg
->cmsg_level
!= SOL_SOCKET
)
204 error(1, 0, "Unexpected cmsg_level %d",
206 switch (cmsg
->cmsg_type
) {
208 actual
.tstamp
= true;
210 case SCM_TIMESTAMPNS
:
211 actual
.tstampns
= true;
213 case SCM_TIMESTAMPING
:
214 ts
= (struct scm_timestamping
*)CMSG_DATA(cmsg
);
215 actual
.swtstamp
= !!ts
->ts
[0].tv_sec
;
216 if (ts
->ts
[1].tv_sec
!= 0)
217 error(0, 0, "ts[1] should not be set.");
218 actual
.hwtstamp
= !!ts
->ts
[2].tv_sec
;
221 error(1, 0, "Unexpected cmsg_type %d", cmsg
->cmsg_type
);
225 #define VALIDATE(field) \
227 if (expected.field != actual.field) { \
228 if (expected.field) \
229 error(0, 0, "Expected " #field " to be set."); \
232 "Expected " #field " to not be set."); \
243 free(recv_iov
.iov_base
);
248 void config_so_flags(int rcv
, struct options o
)
252 if (setsockopt(rcv
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) < 0)
253 error(1, errno
, "Failed to enable SO_REUSEADDR");
255 if (o
.so_timestamp
&&
256 setsockopt(rcv
, SOL_SOCKET
, SO_TIMESTAMP
,
257 &o
.so_timestamp
, sizeof(o
.so_timestamp
)) < 0)
258 error(1, errno
, "Failed to enable SO_TIMESTAMP");
260 if (o
.so_timestampns
&&
261 setsockopt(rcv
, SOL_SOCKET
, SO_TIMESTAMPNS
,
262 &o
.so_timestampns
, sizeof(o
.so_timestampns
)) < 0)
263 error(1, errno
, "Failed to enable SO_TIMESTAMPNS");
265 if (o
.so_timestamping
&&
266 setsockopt(rcv
, SOL_SOCKET
, SO_TIMESTAMPING
,
267 &o
.so_timestamping
, sizeof(o
.so_timestamping
)) < 0)
268 error(1, errno
, "Failed to set SO_TIMESTAMPING");
271 bool run_test_case(struct socket_type s
, struct test_case t
)
273 int port
= (s
.type
== SOCK_RAW
) ? 0 : next_port
++;
274 int read_size
= op_size
;
275 struct sockaddr_in addr
;
279 src
= socket(AF_INET
, s
.type
, s
.protocol
);
281 error(1, errno
, "Failed to open src socket");
283 dst
= socket(AF_INET
, s
.type
, s
.protocol
);
285 error(1, errno
, "Failed to open dst socket");
287 memset(&addr
, 0, sizeof(addr
));
288 addr
.sin_family
= AF_INET
;
289 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
290 addr
.sin_port
= htons(port
);
292 if (bind(dst
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
293 error(1, errno
, "Failed to bind to port %d", port
);
295 if (s
.type
== SOCK_STREAM
&& (listen(dst
, 1) < 0))
296 error(1, errno
, "Failed to listen");
298 if (connect(src
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
299 error(1, errno
, "Failed to connect");
301 if (s
.type
== SOCK_STREAM
) {
302 rcv
= accept(dst
, NULL
, NULL
);
304 error(1, errno
, "Failed to accept");
310 config_so_flags(rcv
, t
.sockopt
);
311 usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */
314 if (s
.type
== SOCK_RAW
)
315 read_size
+= 20; /* for IP header */
316 failed
= do_recv(rcv
, read_size
, t
.expected
);
324 int main(int argc
, char **argv
)
326 bool all_protocols
= true;
327 bool all_tests
= true;
333 while ((opt
= getopt_long(argc
, argv
, "", long_options
,
334 &arg_index
)) != -1) {
337 for (t
= 0; t
< ARRAY_SIZE(test_cases
); t
++) {
339 print_test_case(&test_cases
[t
]);
344 if (t
>= ARRAY_SIZE(test_cases
))
345 error(1, 0, "Invalid test case: %d", t
);
347 test_cases
[t
].enabled
= true;
350 op_size
= atoi(optarg
);
353 all_protocols
= false;
354 socket_types
[2].enabled
= true;
357 all_protocols
= false;
358 socket_types
[1].enabled
= true;
361 all_protocols
= false;
362 socket_types
[0].enabled
= true;
365 error(1, 0, "Failed to parse parameters.");
369 for (s
= 0; s
< ARRAY_SIZE(socket_types
); s
++) {
370 if (!all_protocols
&& !socket_types
[s
].enabled
)
373 printf("Testing %s...\n", socket_types
[s
].friendly_name
);
374 for (t
= 0; t
< ARRAY_SIZE(test_cases
); t
++) {
375 if (!all_tests
&& !test_cases
[t
].enabled
)
378 printf("Starting testcase %d...\n", t
);
379 if (run_test_case(socket_types
[s
], test_cases
[t
])) {
381 printf("FAILURE in test case ");
382 print_test_case(&test_cases
[t
]);