HID: add quirk for Akai MIDImix.
[cascardo/linux.git] / Documentation / networking / timestamping / timestamping.c
1 /*
2  * This program demonstrates how the various time stamping features in
3  * the Linux kernel work. It emulates the behavior of a PTP
4  * implementation in stand-alone master mode by sending PTPv1 Sync
5  * multicasts once every second. It looks for similar packets, but
6  * beyond that doesn't actually implement PTP.
7  *
8  * Outgoing packets are time stamped with SO_TIMESTAMPING with or
9  * without hardware support.
10  *
11  * Incoming packets are time stamped with SO_TIMESTAMPING with or
12  * without hardware support, SIOCGSTAMP[NS] (per-socket time stamp) and
13  * SO_TIMESTAMP[NS].
14  *
15  * Copyright (C) 2009 Intel Corporation.
16  * Author: Patrick Ohly <patrick.ohly@intel.com>
17  *
18  * This program is free software; you can redistribute it and/or modify it
19  * under the terms and conditions of the GNU General Public License,
20  * version 2, as published by the Free Software Foundation.
21  *
22  * This program is distributed in the hope it will be useful, but WITHOUT
23  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24  * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
25  * more details.
26  *
27  * You should have received a copy of the GNU General Public License along with
28  * this program; if not, write to the Free Software Foundation, Inc.,
29  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <string.h>
36
37 #include <sys/time.h>
38 #include <sys/socket.h>
39 #include <sys/select.h>
40 #include <sys/ioctl.h>
41 #include <arpa/inet.h>
42 #include <net/if.h>
43
44 #include <asm/types.h>
45 #include <linux/net_tstamp.h>
46 #include <linux/errqueue.h>
47
48 #ifndef SO_TIMESTAMPING
49 # define SO_TIMESTAMPING         37
50 # define SCM_TIMESTAMPING        SO_TIMESTAMPING
51 #endif
52
53 #ifndef SO_TIMESTAMPNS
54 # define SO_TIMESTAMPNS 35
55 #endif
56
57 #ifndef SIOCGSTAMPNS
58 # define SIOCGSTAMPNS 0x8907
59 #endif
60
61 #ifndef SIOCSHWTSTAMP
62 # define SIOCSHWTSTAMP 0x89b0
63 #endif
64
65 static void usage(const char *error)
66 {
67         if (error)
68                 printf("invalid option: %s\n", error);
69         printf("timestamping interface option*\n\n"
70                "Options:\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_RAW_HARDWARE - request reporting of raw HW time stamps\n"
80                "  SIOCGSTAMP - check last socket time stamp\n"
81                "  SIOCGSTAMPNS - more accurate socket time stamp\n");
82         exit(1);
83 }
84
85 static void bail(const char *error)
86 {
87         printf("%s: %s\n", error, strerror(errno));
88         exit(1);
89 }
90
91 static const unsigned char sync[] = {
92         0x00, 0x01, 0x00, 0x01,
93         0x5f, 0x44, 0x46, 0x4c,
94         0x54, 0x00, 0x00, 0x00,
95         0x00, 0x00, 0x00, 0x00,
96         0x00, 0x00, 0x00, 0x00,
97         0x01, 0x01,
98
99         /* fake uuid */
100         0x00, 0x01,
101         0x02, 0x03, 0x04, 0x05,
102
103         0x00, 0x01, 0x00, 0x37,
104         0x00, 0x00, 0x00, 0x08,
105         0x00, 0x00, 0x00, 0x00,
106         0x49, 0x05, 0xcd, 0x01,
107         0x29, 0xb1, 0x8d, 0xb0,
108         0x00, 0x00, 0x00, 0x00,
109         0x00, 0x01,
110
111         /* fake uuid */
112         0x00, 0x01,
113         0x02, 0x03, 0x04, 0x05,
114
115         0x00, 0x00, 0x00, 0x37,
116         0x00, 0x00, 0x00, 0x04,
117         0x44, 0x46, 0x4c, 0x54,
118         0x00, 0x00, 0xf0, 0x60,
119         0x00, 0x01, 0x00, 0x00,
120         0x00, 0x00, 0x00, 0x01,
121         0x00, 0x00, 0xf0, 0x60,
122         0x00, 0x00, 0x00, 0x00,
123         0x00, 0x00, 0x00, 0x04,
124         0x44, 0x46, 0x4c, 0x54,
125         0x00, 0x01,
126
127         /* fake uuid */
128         0x00, 0x01,
129         0x02, 0x03, 0x04, 0x05,
130
131         0x00, 0x00, 0x00, 0x00,
132         0x00, 0x00, 0x00, 0x00,
133         0x00, 0x00, 0x00, 0x00,
134         0x00, 0x00, 0x00, 0x00
135 };
136
137 static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len)
138 {
139         struct timeval now;
140         int res;
141
142         res = sendto(sock, sync, sizeof(sync), 0,
143                 addr, addr_len);
144         gettimeofday(&now, 0);
145         if (res < 0)
146                 printf("%s: %s\n", "send", strerror(errno));
147         else
148                 printf("%ld.%06ld: sent %d bytes\n",
149                        (long)now.tv_sec, (long)now.tv_usec,
150                        res);
151 }
152
153 static void printpacket(struct msghdr *msg, int res,
154                         char *data,
155                         int sock, int recvmsg_flags,
156                         int siocgstamp, int siocgstampns)
157 {
158         struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
159         struct cmsghdr *cmsg;
160         struct timeval tv;
161         struct timespec ts;
162         struct timeval now;
163
164         gettimeofday(&now, 0);
165
166         printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
167                (long)now.tv_sec, (long)now.tv_usec,
168                (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
169                res,
170                inet_ntoa(from_addr->sin_addr),
171                msg->msg_controllen);
172         for (cmsg = CMSG_FIRSTHDR(msg);
173              cmsg;
174              cmsg = CMSG_NXTHDR(msg, cmsg)) {
175                 printf("   cmsg len %zu: ", cmsg->cmsg_len);
176                 switch (cmsg->cmsg_level) {
177                 case SOL_SOCKET:
178                         printf("SOL_SOCKET ");
179                         switch (cmsg->cmsg_type) {
180                         case SO_TIMESTAMP: {
181                                 struct timeval *stamp =
182                                         (struct timeval *)CMSG_DATA(cmsg);
183                                 printf("SO_TIMESTAMP %ld.%06ld",
184                                        (long)stamp->tv_sec,
185                                        (long)stamp->tv_usec);
186                                 break;
187                         }
188                         case SO_TIMESTAMPNS: {
189                                 struct timespec *stamp =
190                                         (struct timespec *)CMSG_DATA(cmsg);
191                                 printf("SO_TIMESTAMPNS %ld.%09ld",
192                                        (long)stamp->tv_sec,
193                                        (long)stamp->tv_nsec);
194                                 break;
195                         }
196                         case SO_TIMESTAMPING: {
197                                 struct timespec *stamp =
198                                         (struct timespec *)CMSG_DATA(cmsg);
199                                 printf("SO_TIMESTAMPING ");
200                                 printf("SW %ld.%09ld ",
201                                        (long)stamp->tv_sec,
202                                        (long)stamp->tv_nsec);
203                                 stamp++;
204                                 /* skip deprecated HW transformed */
205                                 stamp++;
206                                 printf("HW raw %ld.%09ld",
207                                        (long)stamp->tv_sec,
208                                        (long)stamp->tv_nsec);
209                                 break;
210                         }
211                         default:
212                                 printf("type %d", cmsg->cmsg_type);
213                                 break;
214                         }
215                         break;
216                 case IPPROTO_IP:
217                         printf("IPPROTO_IP ");
218                         switch (cmsg->cmsg_type) {
219                         case IP_RECVERR: {
220                                 struct sock_extended_err *err =
221                                         (struct sock_extended_err *)CMSG_DATA(cmsg);
222                                 printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s",
223                                         strerror(err->ee_errno),
224                                         err->ee_origin,
225 #ifdef SO_EE_ORIGIN_TIMESTAMPING
226                                         err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ?
227                                         "bounced packet" : "unexpected origin"
228 #else
229                                         "probably SO_EE_ORIGIN_TIMESTAMPING"
230 #endif
231                                         );
232                                 if (res < sizeof(sync))
233                                         printf(" => truncated data?!");
234                                 else if (!memcmp(sync, data + res - sizeof(sync),
235                                                         sizeof(sync)))
236                                         printf(" => GOT OUR DATA BACK (HURRAY!)");
237                                 break;
238                         }
239                         case IP_PKTINFO: {
240                                 struct in_pktinfo *pktinfo =
241                                         (struct in_pktinfo *)CMSG_DATA(cmsg);
242                                 printf("IP_PKTINFO interface index %u",
243                                         pktinfo->ipi_ifindex);
244                                 break;
245                         }
246                         default:
247                                 printf("type %d", cmsg->cmsg_type);
248                                 break;
249                         }
250                         break;
251                 default:
252                         printf("level %d type %d",
253                                 cmsg->cmsg_level,
254                                 cmsg->cmsg_type);
255                         break;
256                 }
257                 printf("\n");
258         }
259
260         if (siocgstamp) {
261                 if (ioctl(sock, SIOCGSTAMP, &tv))
262                         printf("   %s: %s\n", "SIOCGSTAMP", strerror(errno));
263                 else
264                         printf("SIOCGSTAMP %ld.%06ld\n",
265                                (long)tv.tv_sec,
266                                (long)tv.tv_usec);
267         }
268         if (siocgstampns) {
269                 if (ioctl(sock, SIOCGSTAMPNS, &ts))
270                         printf("   %s: %s\n", "SIOCGSTAMPNS", strerror(errno));
271                 else
272                         printf("SIOCGSTAMPNS %ld.%09ld\n",
273                                (long)ts.tv_sec,
274                                (long)ts.tv_nsec);
275         }
276 }
277
278 static void recvpacket(int sock, int recvmsg_flags,
279                        int siocgstamp, int siocgstampns)
280 {
281         char data[256];
282         struct msghdr msg;
283         struct iovec entry;
284         struct sockaddr_in from_addr;
285         struct {
286                 struct cmsghdr cm;
287                 char control[512];
288         } control;
289         int res;
290
291         memset(&msg, 0, sizeof(msg));
292         msg.msg_iov = &entry;
293         msg.msg_iovlen = 1;
294         entry.iov_base = data;
295         entry.iov_len = sizeof(data);
296         msg.msg_name = (caddr_t)&from_addr;
297         msg.msg_namelen = sizeof(from_addr);
298         msg.msg_control = &control;
299         msg.msg_controllen = sizeof(control);
300
301         res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
302         if (res < 0) {
303                 printf("%s %s: %s\n",
304                        "recvmsg",
305                        (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
306                        strerror(errno));
307         } else {
308                 printpacket(&msg, res, data,
309                             sock, recvmsg_flags,
310                             siocgstamp, siocgstampns);
311         }
312 }
313
314 int main(int argc, char **argv)
315 {
316         int so_timestamping_flags = 0;
317         int so_timestamp = 0;
318         int so_timestampns = 0;
319         int siocgstamp = 0;
320         int siocgstampns = 0;
321         int ip_multicast_loop = 0;
322         char *interface;
323         int i;
324         int enabled = 1;
325         int sock;
326         struct ifreq device;
327         struct ifreq hwtstamp;
328         struct hwtstamp_config hwconfig, hwconfig_requested;
329         struct sockaddr_in addr;
330         struct ip_mreq imr;
331         struct in_addr iaddr;
332         int val;
333         socklen_t len;
334         struct timeval next;
335
336         if (argc < 2)
337                 usage(0);
338         interface = argv[1];
339
340         for (i = 2; i < argc; i++) {
341                 if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
342                         so_timestamp = 1;
343                 else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
344                         so_timestampns = 1;
345                 else if (!strcasecmp(argv[i], "SIOCGSTAMP"))
346                         siocgstamp = 1;
347                 else if (!strcasecmp(argv[i], "SIOCGSTAMPNS"))
348                         siocgstampns = 1;
349                 else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP"))
350                         ip_multicast_loop = 1;
351                 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE"))
352                         so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
353                 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE"))
354                         so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
355                 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE"))
356                         so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE;
357                 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE"))
358                         so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
359                 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE"))
360                         so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE;
361                 else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE"))
362                         so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
363                 else
364                         usage(argv[i]);
365         }
366
367         sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
368         if (sock < 0)
369                 bail("socket");
370
371         memset(&device, 0, sizeof(device));
372         strncpy(device.ifr_name, interface, sizeof(device.ifr_name));
373         if (ioctl(sock, SIOCGIFADDR, &device) < 0)
374                 bail("getting interface IP address");
375
376         memset(&hwtstamp, 0, sizeof(hwtstamp));
377         strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name));
378         hwtstamp.ifr_data = (void *)&hwconfig;
379         memset(&hwconfig, 0, sizeof(hwconfig));
380         hwconfig.tx_type =
381                 (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ?
382                 HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
383         hwconfig.rx_filter =
384                 (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ?
385                 HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE;
386         hwconfig_requested = hwconfig;
387         if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) {
388                 if ((errno == EINVAL || errno == ENOTSUP) &&
389                     hwconfig_requested.tx_type == HWTSTAMP_TX_OFF &&
390                     hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE)
391                         printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
392                 else
393                         bail("SIOCSHWTSTAMP");
394         }
395         printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
396                hwconfig_requested.tx_type, hwconfig.tx_type,
397                hwconfig_requested.rx_filter, hwconfig.rx_filter);
398
399         /* bind to PTP port */
400         addr.sin_family = AF_INET;
401         addr.sin_addr.s_addr = htonl(INADDR_ANY);
402         addr.sin_port = htons(319 /* PTP event port */);
403         if (bind(sock,
404                  (struct sockaddr *)&addr,
405                  sizeof(struct sockaddr_in)) < 0)
406                 bail("bind");
407
408         /* set multicast group for outgoing packets */
409         inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
410         addr.sin_addr = iaddr;
411         imr.imr_multiaddr.s_addr = iaddr.s_addr;
412         imr.imr_interface.s_addr =
413                 ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
414         if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
415                        &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
416                 bail("set multicast");
417
418         /* join multicast group, loop our own packet */
419         if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
420                        &imr, sizeof(struct ip_mreq)) < 0)
421                 bail("join multicast group");
422
423         if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
424                        &ip_multicast_loop, sizeof(enabled)) < 0) {
425                 bail("loop multicast");
426         }
427
428         /* set socket options for time stamping */
429         if (so_timestamp &&
430                 setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
431                            &enabled, sizeof(enabled)) < 0)
432                 bail("setsockopt SO_TIMESTAMP");
433
434         if (so_timestampns &&
435                 setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
436                            &enabled, sizeof(enabled)) < 0)
437                 bail("setsockopt SO_TIMESTAMPNS");
438
439         if (so_timestamping_flags &&
440                 setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,
441                            &so_timestamping_flags,
442                            sizeof(so_timestamping_flags)) < 0)
443                 bail("setsockopt SO_TIMESTAMPING");
444
445         /* request IP_PKTINFO for debugging purposes */
446         if (setsockopt(sock, SOL_IP, IP_PKTINFO,
447                        &enabled, sizeof(enabled)) < 0)
448                 printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno));
449
450         /* verify socket options */
451         len = sizeof(val);
452         if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
453                 printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
454         else
455                 printf("SO_TIMESTAMP %d\n", val);
456
457         if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
458                 printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS",
459                        strerror(errno));
460         else
461                 printf("SO_TIMESTAMPNS %d\n", val);
462
463         if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) {
464                 printf("%s: %s\n", "getsockopt SO_TIMESTAMPING",
465                        strerror(errno));
466         } else {
467                 printf("SO_TIMESTAMPING %d\n", val);
468                 if (val != so_timestamping_flags)
469                         printf("   not the expected value %d\n",
470                                so_timestamping_flags);
471         }
472
473         /* send packets forever every five seconds */
474         gettimeofday(&next, 0);
475         next.tv_sec = (next.tv_sec + 1) / 5 * 5;
476         next.tv_usec = 0;
477         while (1) {
478                 struct timeval now;
479                 struct timeval delta;
480                 long delta_us;
481                 int res;
482                 fd_set readfs, errorfs;
483
484                 gettimeofday(&now, 0);
485                 delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
486                         (long)(next.tv_usec - now.tv_usec);
487                 if (delta_us > 0) {
488                         /* continue waiting for timeout or data */
489                         delta.tv_sec = delta_us / 1000000;
490                         delta.tv_usec = delta_us % 1000000;
491
492                         FD_ZERO(&readfs);
493                         FD_ZERO(&errorfs);
494                         FD_SET(sock, &readfs);
495                         FD_SET(sock, &errorfs);
496                         printf("%ld.%06ld: select %ldus\n",
497                                (long)now.tv_sec, (long)now.tv_usec,
498                                delta_us);
499                         res = select(sock + 1, &readfs, 0, &errorfs, &delta);
500                         gettimeofday(&now, 0);
501                         printf("%ld.%06ld: select returned: %d, %s\n",
502                                (long)now.tv_sec, (long)now.tv_usec,
503                                res,
504                                res < 0 ? strerror(errno) : "success");
505                         if (res > 0) {
506                                 if (FD_ISSET(sock, &readfs))
507                                         printf("ready for reading\n");
508                                 if (FD_ISSET(sock, &errorfs))
509                                         printf("has error\n");
510                                 recvpacket(sock, 0,
511                                            siocgstamp,
512                                            siocgstampns);
513                                 recvpacket(sock, MSG_ERRQUEUE,
514                                            siocgstamp,
515                                            siocgstampns);
516                         }
517                 } else {
518                         /* write one packet */
519                         sendpacket(sock,
520                                    (struct sockaddr *)&addr,
521                                    sizeof(addr));
522                         next.tv_sec += 5;
523                         continue;
524                 }
525         }
526
527         return 0;
528 }