linux/tools/testing/selftests/net/timestamping.c
<<
>>
Prefs
   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#include <linux/sockios.h>
  48
  49#ifndef SO_TIMESTAMPING
  50# define SO_TIMESTAMPING         37
  51# define SCM_TIMESTAMPING        SO_TIMESTAMPING
  52#endif
  53
  54#ifndef SO_TIMESTAMPNS
  55# define SO_TIMESTAMPNS 35
  56#endif
  57
  58static void usage(const char *error)
  59{
  60        if (error)
  61                printf("invalid option: %s\n", error);
  62        printf("timestamping interface option*\n\n"
  63               "Options:\n"
  64               "  IP_MULTICAST_LOOP - looping outgoing multicasts\n"
  65               "  SO_TIMESTAMP - normal software time stamping, ms resolution\n"
  66               "  SO_TIMESTAMPNS - more accurate software time stamping\n"
  67               "  SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n"
  68               "  SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n"
  69               "  SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n"
  70               "  SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n"
  71               "  SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n"
  72               "  SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
  73               "  SIOCGSTAMP - check last socket time stamp\n"
  74               "  SIOCGSTAMPNS - more accurate socket time stamp\n"
  75               "  PTPV2 - use PTPv2 messages\n");
  76        exit(1);
  77}
  78
  79static void bail(const char *error)
  80{
  81        printf("%s: %s\n", error, strerror(errno));
  82        exit(1);
  83}
  84
  85static const unsigned char sync[] = {
  86        0x00, 0x01, 0x00, 0x01,
  87        0x5f, 0x44, 0x46, 0x4c,
  88        0x54, 0x00, 0x00, 0x00,
  89        0x00, 0x00, 0x00, 0x00,
  90        0x00, 0x00, 0x00, 0x00,
  91        0x01, 0x01,
  92
  93        /* fake uuid */
  94        0x00, 0x01,
  95        0x02, 0x03, 0x04, 0x05,
  96
  97        0x00, 0x01, 0x00, 0x37,
  98        0x00, 0x00, 0x00, 0x08,
  99        0x00, 0x00, 0x00, 0x00,
 100        0x49, 0x05, 0xcd, 0x01,
 101        0x29, 0xb1, 0x8d, 0xb0,
 102        0x00, 0x00, 0x00, 0x00,
 103        0x00, 0x01,
 104
 105        /* fake uuid */
 106        0x00, 0x01,
 107        0x02, 0x03, 0x04, 0x05,
 108
 109        0x00, 0x00, 0x00, 0x37,
 110        0x00, 0x00, 0x00, 0x04,
 111        0x44, 0x46, 0x4c, 0x54,
 112        0x00, 0x00, 0xf0, 0x60,
 113        0x00, 0x01, 0x00, 0x00,
 114        0x00, 0x00, 0x00, 0x01,
 115        0x00, 0x00, 0xf0, 0x60,
 116        0x00, 0x00, 0x00, 0x00,
 117        0x00, 0x00, 0x00, 0x04,
 118        0x44, 0x46, 0x4c, 0x54,
 119        0x00, 0x01,
 120
 121        /* fake uuid */
 122        0x00, 0x01,
 123        0x02, 0x03, 0x04, 0x05,
 124
 125        0x00, 0x00, 0x00, 0x00,
 126        0x00, 0x00, 0x00, 0x00,
 127        0x00, 0x00, 0x00, 0x00,
 128        0x00, 0x00, 0x00, 0x00
 129};
 130
 131static const unsigned char sync_v2[] = {
 132        0x00, 0x02, 0x00, 0x2C,
 133        0x00, 0x00, 0x02, 0x00,
 134        0x00, 0x00, 0x00, 0x00,
 135        0x00, 0x00, 0x00, 0x00,
 136        0x00, 0x00, 0x00, 0x00,
 137        0x00, 0x00, 0x00, 0xFF,
 138        0xFE, 0x00, 0x00, 0x00,
 139        0x00, 0x01, 0x00, 0x01,
 140        0x00, 0x00, 0x00, 0x00,
 141        0x00, 0x00, 0x00, 0x00,
 142        0x00, 0x00, 0x00, 0x00,
 143};
 144
 145static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len, int ptpv2)
 146{
 147        size_t sync_len = ptpv2 ? sizeof(sync_v2) : sizeof(sync);
 148        const void *sync_p = ptpv2 ? sync_v2 : sync;
 149        struct timeval now;
 150        int res;
 151
 152        res = sendto(sock, sync_p, sync_len, 0, addr, addr_len);
 153        gettimeofday(&now, 0);
 154        if (res < 0)
 155                printf("%s: %s\n", "send", strerror(errno));
 156        else
 157                printf("%ld.%06ld: sent %d bytes\n",
 158                       (long)now.tv_sec, (long)now.tv_usec,
 159                       res);
 160}
 161
 162static void printpacket(struct msghdr *msg, int res,
 163                        char *data,
 164                        int sock, int recvmsg_flags,
 165                        int siocgstamp, int siocgstampns, int ptpv2)
 166{
 167        struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
 168        size_t sync_len = ptpv2 ? sizeof(sync_v2) : sizeof(sync);
 169        const void *sync_p = ptpv2 ? sync_v2 : sync;
 170        struct cmsghdr *cmsg;
 171        struct timeval tv;
 172        struct timespec ts;
 173        struct timeval now;
 174
 175        gettimeofday(&now, 0);
 176
 177        printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
 178               (long)now.tv_sec, (long)now.tv_usec,
 179               (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
 180               res,
 181               inet_ntoa(from_addr->sin_addr),
 182               msg->msg_controllen);
 183        for (cmsg = CMSG_FIRSTHDR(msg);
 184             cmsg;
 185             cmsg = CMSG_NXTHDR(msg, cmsg)) {
 186                printf("   cmsg len %zu: ", cmsg->cmsg_len);
 187                switch (cmsg->cmsg_level) {
 188                case SOL_SOCKET:
 189                        printf("SOL_SOCKET ");
 190                        switch (cmsg->cmsg_type) {
 191                        case SO_TIMESTAMP: {
 192                                struct timeval *stamp =
 193                                        (struct timeval *)CMSG_DATA(cmsg);
 194                                printf("SO_TIMESTAMP %ld.%06ld",
 195                                       (long)stamp->tv_sec,
 196                                       (long)stamp->tv_usec);
 197                                break;
 198                        }
 199                        case SO_TIMESTAMPNS: {
 200                                struct timespec *stamp =
 201                                        (struct timespec *)CMSG_DATA(cmsg);
 202                                printf("SO_TIMESTAMPNS %ld.%09ld",
 203                                       (long)stamp->tv_sec,
 204                                       (long)stamp->tv_nsec);
 205                                break;
 206                        }
 207                        case SO_TIMESTAMPING: {
 208                                struct timespec *stamp =
 209                                        (struct timespec *)CMSG_DATA(cmsg);
 210                                printf("SO_TIMESTAMPING ");
 211                                printf("SW %ld.%09ld ",
 212                                       (long)stamp->tv_sec,
 213                                       (long)stamp->tv_nsec);
 214                                stamp++;
 215                                /* skip deprecated HW transformed */
 216                                stamp++;
 217                                printf("HW raw %ld.%09ld",
 218                                       (long)stamp->tv_sec,
 219                                       (long)stamp->tv_nsec);
 220                                break;
 221                        }
 222                        default:
 223                                printf("type %d", cmsg->cmsg_type);
 224                                break;
 225                        }
 226                        break;
 227                case IPPROTO_IP:
 228                        printf("IPPROTO_IP ");
 229                        switch (cmsg->cmsg_type) {
 230                        case IP_RECVERR: {
 231                                struct sock_extended_err *err =
 232                                        (struct sock_extended_err *)CMSG_DATA(cmsg);
 233                                printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s",
 234                                        strerror(err->ee_errno),
 235                                        err->ee_origin,
 236#ifdef SO_EE_ORIGIN_TIMESTAMPING
 237                                        err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ?
 238                                        "bounced packet" : "unexpected origin"
 239#else
 240                                        "probably SO_EE_ORIGIN_TIMESTAMPING"
 241#endif
 242                                        );
 243                                if (res < sync_len)
 244                                        printf(" => truncated data?!");
 245                                else if (!memcmp(sync_p, data + res - sync_len, sync_len))
 246                                        printf(" => GOT OUR DATA BACK (HURRAY!)");
 247                                break;
 248                        }
 249                        case IP_PKTINFO: {
 250                                struct in_pktinfo *pktinfo =
 251                                        (struct in_pktinfo *)CMSG_DATA(cmsg);
 252                                printf("IP_PKTINFO interface index %u",
 253                                        pktinfo->ipi_ifindex);
 254                                break;
 255                        }
 256                        default:
 257                                printf("type %d", cmsg->cmsg_type);
 258                                break;
 259                        }
 260                        break;
 261                default:
 262                        printf("level %d type %d",
 263                                cmsg->cmsg_level,
 264                                cmsg->cmsg_type);
 265                        break;
 266                }
 267                printf("\n");
 268        }
 269
 270        if (siocgstamp) {
 271                if (ioctl(sock, SIOCGSTAMP, &tv))
 272                        printf("   %s: %s\n", "SIOCGSTAMP", strerror(errno));
 273                else
 274                        printf("SIOCGSTAMP %ld.%06ld\n",
 275                               (long)tv.tv_sec,
 276                               (long)tv.tv_usec);
 277        }
 278        if (siocgstampns) {
 279                if (ioctl(sock, SIOCGSTAMPNS, &ts))
 280                        printf("   %s: %s\n", "SIOCGSTAMPNS", strerror(errno));
 281                else
 282                        printf("SIOCGSTAMPNS %ld.%09ld\n",
 283                               (long)ts.tv_sec,
 284                               (long)ts.tv_nsec);
 285        }
 286}
 287
 288static void recvpacket(int sock, int recvmsg_flags,
 289                       int siocgstamp, int siocgstampns, int ptpv2)
 290{
 291        char data[256];
 292        struct msghdr msg;
 293        struct iovec entry;
 294        struct sockaddr_in from_addr;
 295        struct {
 296                struct cmsghdr cm;
 297                char control[512];
 298        } control;
 299        int res;
 300
 301        memset(&msg, 0, sizeof(msg));
 302        msg.msg_iov = &entry;
 303        msg.msg_iovlen = 1;
 304        entry.iov_base = data;
 305        entry.iov_len = sizeof(data);
 306        msg.msg_name = (caddr_t)&from_addr;
 307        msg.msg_namelen = sizeof(from_addr);
 308        msg.msg_control = &control;
 309        msg.msg_controllen = sizeof(control);
 310
 311        res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
 312        if (res < 0) {
 313                printf("%s %s: %s\n",
 314                       "recvmsg",
 315                       (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
 316                       strerror(errno));
 317        } else {
 318                printpacket(&msg, res, data,
 319                            sock, recvmsg_flags,
 320                            siocgstamp, siocgstampns, ptpv2);
 321        }
 322}
 323
 324int main(int argc, char **argv)
 325{
 326        int so_timestamping_flags = 0;
 327        int so_timestamp = 0;
 328        int so_timestampns = 0;
 329        int siocgstamp = 0;
 330        int siocgstampns = 0;
 331        int ip_multicast_loop = 0;
 332        int ptpv2 = 0;
 333        char *interface;
 334        int i;
 335        int enabled = 1;
 336        int sock;
 337        struct ifreq device;
 338        struct ifreq hwtstamp;
 339        struct hwtstamp_config hwconfig, hwconfig_requested;
 340        struct sockaddr_in addr;
 341        struct ip_mreq imr;
 342        struct in_addr iaddr;
 343        int val;
 344        socklen_t len;
 345        struct timeval next;
 346        size_t if_len;
 347
 348        if (argc < 2)
 349                usage(0);
 350        interface = argv[1];
 351        if_len = strlen(interface);
 352        if (if_len >= IFNAMSIZ) {
 353                printf("interface name exceeds IFNAMSIZ\n");
 354                exit(1);
 355        }
 356
 357        for (i = 2; i < argc; i++) {
 358                if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
 359                        so_timestamp = 1;
 360                else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
 361                        so_timestampns = 1;
 362                else if (!strcasecmp(argv[i], "SIOCGSTAMP"))
 363                        siocgstamp = 1;
 364                else if (!strcasecmp(argv[i], "SIOCGSTAMPNS"))
 365                        siocgstampns = 1;
 366                else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP"))
 367                        ip_multicast_loop = 1;
 368                else if (!strcasecmp(argv[i], "PTPV2"))
 369                        ptpv2 = 1;
 370                else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE"))
 371                        so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
 372                else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE"))
 373                        so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
 374                else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE"))
 375                        so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE;
 376                else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE"))
 377                        so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
 378                else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE"))
 379                        so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE;
 380                else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE"))
 381                        so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
 382                else
 383                        usage(argv[i]);
 384        }
 385
 386        sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
 387        if (sock < 0)
 388                bail("socket");
 389
 390        memset(&device, 0, sizeof(device));
 391        memcpy(device.ifr_name, interface, if_len + 1);
 392        if (ioctl(sock, SIOCGIFADDR, &device) < 0)
 393                bail("getting interface IP address");
 394
 395        memset(&hwtstamp, 0, sizeof(hwtstamp));
 396        memcpy(hwtstamp.ifr_name, interface, if_len + 1);
 397        hwtstamp.ifr_data = (void *)&hwconfig;
 398        memset(&hwconfig, 0, sizeof(hwconfig));
 399        hwconfig.tx_type =
 400                (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ?
 401                HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
 402        hwconfig.rx_filter =
 403                (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ?
 404                ptpv2 ? HWTSTAMP_FILTER_PTP_V2_L4_SYNC :
 405                HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE;
 406        hwconfig_requested = hwconfig;
 407        if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) {
 408                if ((errno == EINVAL || errno == ENOTSUP) &&
 409                    hwconfig_requested.tx_type == HWTSTAMP_TX_OFF &&
 410                    hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE)
 411                        printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
 412                else
 413                        bail("SIOCSHWTSTAMP");
 414        }
 415        printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
 416               hwconfig_requested.tx_type, hwconfig.tx_type,
 417               hwconfig_requested.rx_filter, hwconfig.rx_filter);
 418
 419        /* bind to PTP port */
 420        addr.sin_family = AF_INET;
 421        addr.sin_addr.s_addr = htonl(INADDR_ANY);
 422        addr.sin_port = htons(319 /* PTP event port */);
 423        if (bind(sock,
 424                 (struct sockaddr *)&addr,
 425                 sizeof(struct sockaddr_in)) < 0)
 426                bail("bind");
 427
 428        /* set multicast group for outgoing packets */
 429        inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
 430        addr.sin_addr = iaddr;
 431        imr.imr_multiaddr.s_addr = iaddr.s_addr;
 432        imr.imr_interface.s_addr =
 433                ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
 434        if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
 435                       &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
 436                bail("set multicast");
 437
 438        /* join multicast group, loop our own packet */
 439        if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
 440                       &imr, sizeof(struct ip_mreq)) < 0)
 441                bail("join multicast group");
 442
 443        if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
 444                       &ip_multicast_loop, sizeof(enabled)) < 0) {
 445                bail("loop multicast");
 446        }
 447
 448        /* set socket options for time stamping */
 449        if (so_timestamp &&
 450                setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
 451                           &enabled, sizeof(enabled)) < 0)
 452                bail("setsockopt SO_TIMESTAMP");
 453
 454        if (so_timestampns &&
 455                setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
 456                           &enabled, sizeof(enabled)) < 0)
 457                bail("setsockopt SO_TIMESTAMPNS");
 458
 459        if (so_timestamping_flags &&
 460                setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,
 461                           &so_timestamping_flags,
 462                           sizeof(so_timestamping_flags)) < 0)
 463                bail("setsockopt SO_TIMESTAMPING");
 464
 465        /* request IP_PKTINFO for debugging purposes */
 466        if (setsockopt(sock, SOL_IP, IP_PKTINFO,
 467                       &enabled, sizeof(enabled)) < 0)
 468                printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno));
 469
 470        /* verify socket options */
 471        len = sizeof(val);
 472        if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
 473                printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
 474        else
 475                printf("SO_TIMESTAMP %d\n", val);
 476
 477        if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
 478                printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS",
 479                       strerror(errno));
 480        else
 481                printf("SO_TIMESTAMPNS %d\n", val);
 482
 483        if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) {
 484                printf("%s: %s\n", "getsockopt SO_TIMESTAMPING",
 485                       strerror(errno));
 486        } else {
 487                printf("SO_TIMESTAMPING %d\n", val);
 488                if (val != so_timestamping_flags)
 489                        printf("   not the expected value %d\n",
 490                               so_timestamping_flags);
 491        }
 492
 493        /* send packets forever every five seconds */
 494        gettimeofday(&next, 0);
 495        next.tv_sec = (next.tv_sec + 1) / 5 * 5;
 496        next.tv_usec = 0;
 497        while (1) {
 498                struct timeval now;
 499                struct timeval delta;
 500                long delta_us;
 501                int res;
 502                fd_set readfs, errorfs;
 503
 504                gettimeofday(&now, 0);
 505                delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
 506                        (long)(next.tv_usec - now.tv_usec);
 507                if (delta_us > 0) {
 508                        /* continue waiting for timeout or data */
 509                        delta.tv_sec = delta_us / 1000000;
 510                        delta.tv_usec = delta_us % 1000000;
 511
 512                        FD_ZERO(&readfs);
 513                        FD_ZERO(&errorfs);
 514                        FD_SET(sock, &readfs);
 515                        FD_SET(sock, &errorfs);
 516                        printf("%ld.%06ld: select %ldus\n",
 517                               (long)now.tv_sec, (long)now.tv_usec,
 518                               delta_us);
 519                        res = select(sock + 1, &readfs, 0, &errorfs, &delta);
 520                        gettimeofday(&now, 0);
 521                        printf("%ld.%06ld: select returned: %d, %s\n",
 522                               (long)now.tv_sec, (long)now.tv_usec,
 523                               res,
 524                               res < 0 ? strerror(errno) : "success");
 525                        if (res > 0) {
 526                                if (FD_ISSET(sock, &readfs))
 527                                        printf("ready for reading\n");
 528                                if (FD_ISSET(sock, &errorfs))
 529                                        printf("has error\n");
 530                                recvpacket(sock, 0,
 531                                           siocgstamp,
 532                                           siocgstampns, ptpv2);
 533                                recvpacket(sock, MSG_ERRQUEUE,
 534                                           siocgstamp,
 535                                           siocgstampns, ptpv2);
 536                        }
 537                } else {
 538                        /* write one packet */
 539                        sendpacket(sock,
 540                                   (struct sockaddr *)&addr,
 541                                   sizeof(addr), ptpv2);
 542                        next.tv_sec += 5;
 543                        continue;
 544                }
 545        }
 546
 547        return 0;
 548}
 549