38 #include <sys/socket.h>
39 #include <sys/select.h>
40 #include <sys/ioctl.h>
41 #include <arpa/inet.h>
44 #include <asm/types.h>
46 #include <linux/errqueue.h>
48 #ifndef SO_TIMESTAMPING
49 # define SO_TIMESTAMPING 37
50 # define SCM_TIMESTAMPING SO_TIMESTAMPING
53 #ifndef SO_TIMESTAMPNS
54 # define SO_TIMESTAMPNS 35
58 # define SIOCGSTAMPNS 0x8907
62 # define SIOCSHWTSTAMP 0x89b0
68 printf(
"invalid option: %s\n", error);
69 printf(
"timestamping interface option*\n\n"
71 " IP_MULTICAST_LOOP - looping outgoing multicasts\n"
72 " SO_TIMESTAMP - normal software time stamping, ms resolution\n"
73 " SO_TIMESTAMPNS - more accurate software time stamping\n"
74 " SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n"
75 " SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n"
76 " SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n"
77 " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n"
78 " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n"
79 " SOF_TIMESTAMPING_SYS_HARDWARE - request reporting of transformed HW time stamps\n"
80 " SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
81 " SIOCGSTAMP - check last socket time stamp\n"
82 " SIOCGSTAMPNS - more accurate socket time stamp\n");
86 static void bail(
const char *
error)
92 static const unsigned char sync[] = {
93 0x00, 0x01, 0x00, 0x01,
94 0x5f, 0x44, 0x46, 0x4c,
95 0x54, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00,
102 0x02, 0x03, 0x04, 0x05,
104 0x00, 0x01, 0x00, 0x37,
105 0x00, 0x00, 0x00, 0x08,
106 0x00, 0x00, 0x00, 0x00,
107 0x49, 0x05, 0xcd, 0x01,
108 0x29, 0xb1, 0x8d, 0xb0,
109 0x00, 0x00, 0x00, 0x00,
114 0x02, 0x03, 0x04, 0x05,
116 0x00, 0x00, 0x00, 0x37,
117 0x00, 0x00, 0x00, 0x04,
118 0x44, 0x46, 0x4c, 0x54,
119 0x00, 0x00, 0xf0, 0x60,
120 0x00, 0x01, 0x00, 0x00,
121 0x00, 0x00, 0x00, 0x01,
122 0x00, 0x00, 0xf0, 0x60,
123 0x00, 0x00, 0x00, 0x00,
124 0x00, 0x00, 0x00, 0x04,
125 0x44, 0x46, 0x4c, 0x54,
130 0x02, 0x03, 0x04, 0x05,
132 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x00, 0x00, 0x00
143 res = sendto(sock, sync,
sizeof(sync), 0,
149 printf(
"%ld.%06ld: sent %d bytes\n",
150 (
long)now.tv_sec, (
long)now.tv_usec,
154 static void printpacket(
struct msghdr *
msg,
int res,
156 int sock,
int recvmsg_flags,
157 int siocgstamp,
int siocgstampns)
167 printf(
"%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
168 (
long)now.tv_sec, (
long)now.tv_usec,
176 printf(
" cmsg len %zu: ", cmsg->cmsg_len);
177 switch (cmsg->cmsg_level) {
180 switch (cmsg->cmsg_type) {
184 printf(
"SO_TIMESTAMP %ld.%06ld",
192 printf(
"SO_TIMESTAMPNS %ld.%09ld",
200 printf(
"SO_TIMESTAMPING ");
205 printf(
"HW transformed %ld.%09ld ",
209 printf(
"HW raw %ld.%09ld",
215 printf(
"type %d", cmsg->cmsg_type);
221 switch (cmsg->cmsg_type) {
225 printf(
"IP_RECVERR ee_errno '%s' ee_origin %d => %s",
230 "bounced packet" :
"unexpected origin"
232 "probably SO_EE_ORIGIN_TIMESTAMPING"
235 if (res <
sizeof(sync))
236 printf(
" => truncated data?!");
237 else if (!
memcmp(sync, data + res -
sizeof(sync),
239 printf(
" => GOT OUR DATA BACK (HURRAY!)");
245 printf(
"IP_PKTINFO interface index %u",
250 printf(
"type %d", cmsg->cmsg_type);
255 printf(
"level %d type %d",
267 printf(
"SIOCGSTAMP %ld.%06ld\n",
275 printf(
"SIOCGSTAMPNS %ld.%09ld\n",
281 static void recvpacket(
int sock,
int recvmsg_flags,
282 int siocgstamp,
int siocgstampns)
294 memset(&msg, 0,
sizeof(msg));
308 (recvmsg_flags & MSG_ERRQUEUE) ?
"error" :
"regular",
311 printpacket(&msg, res, data,
313 siocgstamp, siocgstampns);
319 int so_timestamping_flags = 0;
320 int so_timestamp = 0;
321 int so_timestampns = 0;
323 int siocgstampns = 0;
324 int ip_multicast_loop = 0;
330 struct ifreq hwtstamp;
343 for (i = 2; i <
argc; i++) {
346 else if (!
strcasecmp(argv[i],
"SO_TIMESTAMPNS"))
350 else if (!
strcasecmp(argv[i],
"SIOCGSTAMPNS"))
352 else if (!
strcasecmp(argv[i],
"IP_MULTICAST_LOOP"))
353 ip_multicast_loop = 1;
354 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_TX_HARDWARE"))
356 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_TX_SOFTWARE"))
358 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_RX_HARDWARE"))
360 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_RX_SOFTWARE"))
362 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_SOFTWARE"))
364 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_SYS_HARDWARE"))
366 else if (!
strcasecmp(argv[i],
"SOF_TIMESTAMPING_RAW_HARDWARE"))
376 memset(&device, 0,
sizeof(device));
377 strncpy(device.ifr_name, interface,
sizeof(device.ifr_name));
379 bail(
"getting interface IP address");
381 memset(&hwtstamp, 0,
sizeof(hwtstamp));
382 strncpy(hwtstamp.ifr_name, interface,
sizeof(hwtstamp.ifr_name));
383 hwtstamp.ifr_data = (
void *)&hwconfig;
384 memset(&hwconfig, 0,
sizeof(hwconfig));
391 hwconfig_requested = hwconfig;
396 printf(
"SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
398 bail(
"SIOCSHWTSTAMP");
400 printf(
"SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
414 inet_aton(
"224.0.1.130", &iaddr);
418 ((
struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
421 bail(
"set multicast");
425 &imr,
sizeof(
struct ip_mreq)) < 0)
426 bail(
"join multicast group");
429 &ip_multicast_loop,
sizeof(enabled)) < 0) {
430 bail(
"loop multicast");
436 &enabled,
sizeof(enabled)) < 0)
437 bail(
"setsockopt SO_TIMESTAMP");
439 if (so_timestampns &&
441 &enabled,
sizeof(enabled)) < 0)
442 bail(
"setsockopt SO_TIMESTAMPNS");
444 if (so_timestamping_flags &&
446 &so_timestamping_flags,
447 sizeof(so_timestamping_flags)) < 0)
448 bail(
"setsockopt SO_TIMESTAMPING");
452 &enabled,
sizeof(enabled)) < 0)
460 printf(
"SO_TIMESTAMP %d\n", val);
463 printf(
"%s: %s\n",
"getsockopt SO_TIMESTAMPNS",
466 printf(
"SO_TIMESTAMPNS %d\n", val);
469 printf(
"%s: %s\n",
"getsockopt SO_TIMESTAMPING",
472 printf(
"SO_TIMESTAMPING %d\n", val);
473 if (val != so_timestamping_flags)
474 printf(
" not the expected value %d\n",
475 so_timestamping_flags);
494 delta.
tv_sec = delta_us / 1000000;
495 delta.
tv_usec = delta_us % 1000000;
499 FD_SET(sock, &readfs);
500 FD_SET(sock, &errorfs);
501 printf(
"%ld.%06ld: select %ldus\n",
504 res =
select(sock + 1, &readfs, 0, &errorfs, &delta);
506 printf(
"%ld.%06ld: select returned: %d, %s\n",
511 if (FD_ISSET(sock, &readfs))
512 printf(
"ready for reading\n");
513 if (FD_ISSET(sock, &errorfs))
518 recvpacket(sock, MSG_ERRQUEUE,