root/tools/testing/selftests/networking/timestamping/txtimestamp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. timespec_to_us64
  2. validate_key
  3. validate_timestamp
  4. __print_timestamp
  5. print_timestamp_usr
  6. print_timestamp
  7. print_payload
  8. print_pktinfo
  9. __poll
  10. __recv_errmsg_cmsg
  11. recv_errmsg
  12. get_ip_csum
  13. get_udp_csum
  14. fill_header_ipv4
  15. fill_header_ipv6
  16. fill_header_udp
  17. do_test
  18. usage
  19. parse_opt
  20. resolve_hostname
  21. do_listen
  22. do_main
  23. main

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright 2014 Google Inc.
   4  * Author: willemb@google.com (Willem de Bruijn)
   5  *
   6  * Test software tx timestamping, including
   7  *
   8  * - SCHED, SND and ACK timestamps
   9  * - RAW, UDP and TCP
  10  * - IPv4 and IPv6
  11  * - various packet sizes (to test GSO and TSO)
  12  *
  13  * Consult the command line arguments for help on running
  14  * the various testcases.
  15  *
  16  * This test requires a dummy TCP server.
  17  * A simple `nc6 [-u] -l -p $DESTPORT` will do
  18  */
  19 
  20 #define _GNU_SOURCE
  21 
  22 #include <arpa/inet.h>
  23 #include <asm/types.h>
  24 #include <error.h>
  25 #include <errno.h>
  26 #include <inttypes.h>
  27 #include <linux/errqueue.h>
  28 #include <linux/if_ether.h>
  29 #include <linux/ipv6.h>
  30 #include <linux/net_tstamp.h>
  31 #include <netdb.h>
  32 #include <net/if.h>
  33 #include <netinet/in.h>
  34 #include <netinet/ip.h>
  35 #include <netinet/udp.h>
  36 #include <netinet/tcp.h>
  37 #include <netpacket/packet.h>
  38 #include <poll.h>
  39 #include <stdarg.h>
  40 #include <stdbool.h>
  41 #include <stdio.h>
  42 #include <stdlib.h>
  43 #include <string.h>
  44 #include <sys/ioctl.h>
  45 #include <sys/select.h>
  46 #include <sys/socket.h>
  47 #include <sys/time.h>
  48 #include <sys/types.h>
  49 #include <time.h>
  50 #include <unistd.h>
  51 
  52 /* command line parameters */
  53 static int cfg_proto = SOCK_STREAM;
  54 static int cfg_ipproto = IPPROTO_TCP;
  55 static int cfg_num_pkts = 4;
  56 static int do_ipv4 = 1;
  57 static int do_ipv6 = 1;
  58 static int cfg_payload_len = 10;
  59 static int cfg_poll_timeout = 100;
  60 static int cfg_delay_snd;
  61 static int cfg_delay_ack;
  62 static bool cfg_show_payload;
  63 static bool cfg_do_pktinfo;
  64 static bool cfg_loop_nodata;
  65 static bool cfg_no_delay;
  66 static bool cfg_use_cmsg;
  67 static bool cfg_use_pf_packet;
  68 static bool cfg_do_listen;
  69 static uint16_t dest_port = 9000;
  70 
  71 static struct sockaddr_in daddr;
  72 static struct sockaddr_in6 daddr6;
  73 static struct timespec ts_usr;
  74 
  75 static int saved_tskey = -1;
  76 static int saved_tskey_type = -1;
  77 
  78 static bool test_failed;
  79 
  80 static int64_t timespec_to_us64(struct timespec *ts)
  81 {
  82         return ts->tv_sec * 1000 * 1000 + ts->tv_nsec / 1000;
  83 }
  84 
  85 static void validate_key(int tskey, int tstype)
  86 {
  87         int stepsize;
  88 
  89         /* compare key for each subsequent request
  90          * must only test for one type, the first one requested
  91          */
  92         if (saved_tskey == -1)
  93                 saved_tskey_type = tstype;
  94         else if (saved_tskey_type != tstype)
  95                 return;
  96 
  97         stepsize = cfg_proto == SOCK_STREAM ? cfg_payload_len : 1;
  98         if (tskey != saved_tskey + stepsize) {
  99                 fprintf(stderr, "ERROR: key %d, expected %d\n",
 100                                 tskey, saved_tskey + stepsize);
 101                 test_failed = true;
 102         }
 103 
 104         saved_tskey = tskey;
 105 }
 106 
 107 static void validate_timestamp(struct timespec *cur, int min_delay)
 108 {
 109         int max_delay = min_delay + 500 /* processing time upper bound */;
 110         int64_t cur64, start64;
 111 
 112         cur64 = timespec_to_us64(cur);
 113         start64 = timespec_to_us64(&ts_usr);
 114 
 115         if (cur64 < start64 + min_delay || cur64 > start64 + max_delay) {
 116                 fprintf(stderr, "ERROR: delay %lu expected between %d and %d\n",
 117                                 cur64 - start64, min_delay, max_delay);
 118                 test_failed = true;
 119         }
 120 }
 121 
 122 static void __print_timestamp(const char *name, struct timespec *cur,
 123                               uint32_t key, int payload_len)
 124 {
 125         if (!(cur->tv_sec | cur->tv_nsec))
 126                 return;
 127 
 128         fprintf(stderr, "  %s: %lu s %lu us (seq=%u, len=%u)",
 129                         name, cur->tv_sec, cur->tv_nsec / 1000,
 130                         key, payload_len);
 131 
 132         if (cur != &ts_usr)
 133                 fprintf(stderr, "  (USR %+" PRId64 " us)",
 134                         timespec_to_us64(cur) - timespec_to_us64(&ts_usr));
 135 
 136         fprintf(stderr, "\n");
 137 }
 138 
 139 static void print_timestamp_usr(void)
 140 {
 141         if (clock_gettime(CLOCK_REALTIME, &ts_usr))
 142                 error(1, errno, "clock_gettime");
 143 
 144         __print_timestamp("  USR", &ts_usr, 0, 0);
 145 }
 146 
 147 static void print_timestamp(struct scm_timestamping *tss, int tstype,
 148                             int tskey, int payload_len)
 149 {
 150         const char *tsname;
 151 
 152         validate_key(tskey, tstype);
 153 
 154         switch (tstype) {
 155         case SCM_TSTAMP_SCHED:
 156                 tsname = "  ENQ";
 157                 validate_timestamp(&tss->ts[0], 0);
 158                 break;
 159         case SCM_TSTAMP_SND:
 160                 tsname = "  SND";
 161                 validate_timestamp(&tss->ts[0], cfg_delay_snd);
 162                 break;
 163         case SCM_TSTAMP_ACK:
 164                 tsname = "  ACK";
 165                 validate_timestamp(&tss->ts[0], cfg_delay_ack);
 166                 break;
 167         default:
 168                 error(1, 0, "unknown timestamp type: %u",
 169                 tstype);
 170         }
 171         __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
 172 }
 173 
 174 /* TODO: convert to check_and_print payload once API is stable */
 175 static void print_payload(char *data, int len)
 176 {
 177         int i;
 178 
 179         if (!len)
 180                 return;
 181 
 182         if (len > 70)
 183                 len = 70;
 184 
 185         fprintf(stderr, "payload: ");
 186         for (i = 0; i < len; i++)
 187                 fprintf(stderr, "%02hhx ", data[i]);
 188         fprintf(stderr, "\n");
 189 }
 190 
 191 static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr)
 192 {
 193         char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN];
 194 
 195         fprintf(stderr, "         pktinfo: ifindex=%u src=%s dst=%s\n",
 196                 ifindex,
 197                 saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown",
 198                 daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown");
 199 }
 200 
 201 static void __poll(int fd)
 202 {
 203         struct pollfd pollfd;
 204         int ret;
 205 
 206         memset(&pollfd, 0, sizeof(pollfd));
 207         pollfd.fd = fd;
 208         ret = poll(&pollfd, 1, cfg_poll_timeout);
 209         if (ret != 1)
 210                 error(1, errno, "poll");
 211 }
 212 
 213 static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
 214 {
 215         struct sock_extended_err *serr = NULL;
 216         struct scm_timestamping *tss = NULL;
 217         struct cmsghdr *cm;
 218         int batch = 0;
 219 
 220         for (cm = CMSG_FIRSTHDR(msg);
 221              cm && cm->cmsg_len;
 222              cm = CMSG_NXTHDR(msg, cm)) {
 223                 if (cm->cmsg_level == SOL_SOCKET &&
 224                     cm->cmsg_type == SCM_TIMESTAMPING) {
 225                         tss = (void *) CMSG_DATA(cm);
 226                 } else if ((cm->cmsg_level == SOL_IP &&
 227                             cm->cmsg_type == IP_RECVERR) ||
 228                            (cm->cmsg_level == SOL_IPV6 &&
 229                             cm->cmsg_type == IPV6_RECVERR) ||
 230                            (cm->cmsg_level == SOL_PACKET &&
 231                             cm->cmsg_type == PACKET_TX_TIMESTAMP)) {
 232                         serr = (void *) CMSG_DATA(cm);
 233                         if (serr->ee_errno != ENOMSG ||
 234                             serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
 235                                 fprintf(stderr, "unknown ip error %d %d\n",
 236                                                 serr->ee_errno,
 237                                                 serr->ee_origin);
 238                                 serr = NULL;
 239                         }
 240                 } else if (cm->cmsg_level == SOL_IP &&
 241                            cm->cmsg_type == IP_PKTINFO) {
 242                         struct in_pktinfo *info = (void *) CMSG_DATA(cm);
 243                         print_pktinfo(AF_INET, info->ipi_ifindex,
 244                                       &info->ipi_spec_dst, &info->ipi_addr);
 245                 } else if (cm->cmsg_level == SOL_IPV6 &&
 246                            cm->cmsg_type == IPV6_PKTINFO) {
 247                         struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm);
 248                         print_pktinfo(AF_INET6, info6->ipi6_ifindex,
 249                                       NULL, &info6->ipi6_addr);
 250                 } else
 251                         fprintf(stderr, "unknown cmsg %d,%d\n",
 252                                         cm->cmsg_level, cm->cmsg_type);
 253 
 254                 if (serr && tss) {
 255                         print_timestamp(tss, serr->ee_info, serr->ee_data,
 256                                         payload_len);
 257                         serr = NULL;
 258                         tss = NULL;
 259                         batch++;
 260                 }
 261         }
 262 
 263         if (batch > 1)
 264                 fprintf(stderr, "batched %d timestamps\n", batch);
 265 }
 266 
 267 static int recv_errmsg(int fd)
 268 {
 269         static char ctrl[1024 /* overprovision*/];
 270         static struct msghdr msg;
 271         struct iovec entry;
 272         static char *data;
 273         int ret = 0;
 274 
 275         data = malloc(cfg_payload_len);
 276         if (!data)
 277                 error(1, 0, "malloc");
 278 
 279         memset(&msg, 0, sizeof(msg));
 280         memset(&entry, 0, sizeof(entry));
 281         memset(ctrl, 0, sizeof(ctrl));
 282 
 283         entry.iov_base = data;
 284         entry.iov_len = cfg_payload_len;
 285         msg.msg_iov = &entry;
 286         msg.msg_iovlen = 1;
 287         msg.msg_name = NULL;
 288         msg.msg_namelen = 0;
 289         msg.msg_control = ctrl;
 290         msg.msg_controllen = sizeof(ctrl);
 291 
 292         ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
 293         if (ret == -1 && errno != EAGAIN)
 294                 error(1, errno, "recvmsg");
 295 
 296         if (ret >= 0) {
 297                 __recv_errmsg_cmsg(&msg, ret);
 298                 if (cfg_show_payload)
 299                         print_payload(data, cfg_payload_len);
 300         }
 301 
 302         free(data);
 303         return ret == -1;
 304 }
 305 
 306 static uint16_t get_ip_csum(const uint16_t *start, int num_words,
 307                             unsigned long sum)
 308 {
 309         int i;
 310 
 311         for (i = 0; i < num_words; i++)
 312                 sum += start[i];
 313 
 314         while (sum >> 16)
 315                 sum = (sum & 0xFFFF) + (sum >> 16);
 316 
 317         return ~sum;
 318 }
 319 
 320 static uint16_t get_udp_csum(const struct udphdr *udph, int alen)
 321 {
 322         unsigned long pseudo_sum, csum_len;
 323         const void *csum_start = udph;
 324 
 325         pseudo_sum = htons(IPPROTO_UDP);
 326         pseudo_sum += udph->len;
 327 
 328         /* checksum ip(v6) addresses + udp header + payload */
 329         csum_start -= alen * 2;
 330         csum_len = ntohs(udph->len) + alen * 2;
 331 
 332         return get_ip_csum(csum_start, csum_len >> 1, pseudo_sum);
 333 }
 334 
 335 static int fill_header_ipv4(void *p)
 336 {
 337         struct iphdr *iph = p;
 338 
 339         memset(iph, 0, sizeof(*iph));
 340 
 341         iph->ihl        = 5;
 342         iph->version    = 4;
 343         iph->ttl        = 2;
 344         iph->saddr      = daddr.sin_addr.s_addr;        /* set for udp csum calc */
 345         iph->daddr      = daddr.sin_addr.s_addr;
 346         iph->protocol   = IPPROTO_UDP;
 347 
 348         /* kernel writes saddr, csum, len */
 349 
 350         return sizeof(*iph);
 351 }
 352 
 353 static int fill_header_ipv6(void *p)
 354 {
 355         struct ipv6hdr *ip6h = p;
 356 
 357         memset(ip6h, 0, sizeof(*ip6h));
 358 
 359         ip6h->version           = 6;
 360         ip6h->payload_len       = htons(sizeof(struct udphdr) + cfg_payload_len);
 361         ip6h->nexthdr           = IPPROTO_UDP;
 362         ip6h->hop_limit         = 64;
 363 
 364         ip6h->saddr             = daddr6.sin6_addr;
 365         ip6h->daddr             = daddr6.sin6_addr;
 366 
 367         /* kernel does not write saddr in case of ipv6 */
 368 
 369         return sizeof(*ip6h);
 370 }
 371 
 372 static void fill_header_udp(void *p, bool is_ipv4)
 373 {
 374         struct udphdr *udph = p;
 375 
 376         udph->source = ntohs(dest_port + 1);    /* spoof */
 377         udph->dest   = ntohs(dest_port);
 378         udph->len    = ntohs(sizeof(*udph) + cfg_payload_len);
 379         udph->check  = 0;
 380 
 381         udph->check  = get_udp_csum(udph, is_ipv4 ? sizeof(struct in_addr) :
 382                                                     sizeof(struct in6_addr));
 383 }
 384 
 385 static void do_test(int family, unsigned int report_opt)
 386 {
 387         char control[CMSG_SPACE(sizeof(uint32_t))];
 388         struct sockaddr_ll laddr;
 389         unsigned int sock_opt;
 390         struct cmsghdr *cmsg;
 391         struct msghdr msg;
 392         struct iovec iov;
 393         char *buf;
 394         int fd, i, val = 1, total_len;
 395 
 396         total_len = cfg_payload_len;
 397         if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) {
 398                 total_len += sizeof(struct udphdr);
 399                 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW)
 400                         if (family == PF_INET)
 401                                 total_len += sizeof(struct iphdr);
 402                         else
 403                                 total_len += sizeof(struct ipv6hdr);
 404 
 405                 /* special case, only rawv6_sendmsg:
 406                  * pass proto in sin6_port if not connected
 407                  * also see ANK comment in net/ipv4/raw.c
 408                  */
 409                 daddr6.sin6_port = htons(cfg_ipproto);
 410         }
 411 
 412         buf = malloc(total_len);
 413         if (!buf)
 414                 error(1, 0, "malloc");
 415 
 416         fd = socket(cfg_use_pf_packet ? PF_PACKET : family,
 417                     cfg_proto, cfg_ipproto);
 418         if (fd < 0)
 419                 error(1, errno, "socket");
 420 
 421         /* reset expected key on each new socket */
 422         saved_tskey = -1;
 423 
 424         if (cfg_proto == SOCK_STREAM) {
 425                 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
 426                                (char*) &val, sizeof(val)))
 427                         error(1, 0, "setsockopt no nagle");
 428 
 429                 if (family == PF_INET) {
 430                         if (connect(fd, (void *) &daddr, sizeof(daddr)))
 431                                 error(1, errno, "connect ipv4");
 432                 } else {
 433                         if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
 434                                 error(1, errno, "connect ipv6");
 435                 }
 436         }
 437 
 438         if (cfg_do_pktinfo) {
 439                 if (family == AF_INET6) {
 440                         if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO,
 441                                        &val, sizeof(val)))
 442                                 error(1, errno, "setsockopt pktinfo ipv6");
 443                 } else {
 444                         if (setsockopt(fd, SOL_IP, IP_PKTINFO,
 445                                        &val, sizeof(val)))
 446                                 error(1, errno, "setsockopt pktinfo ipv4");
 447                 }
 448         }
 449 
 450         sock_opt = SOF_TIMESTAMPING_SOFTWARE |
 451                    SOF_TIMESTAMPING_OPT_CMSG |
 452                    SOF_TIMESTAMPING_OPT_ID;
 453 
 454         if (!cfg_use_cmsg)
 455                 sock_opt |= report_opt;
 456 
 457         if (cfg_loop_nodata)
 458                 sock_opt |= SOF_TIMESTAMPING_OPT_TSONLY;
 459 
 460         if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
 461                        (char *) &sock_opt, sizeof(sock_opt)))
 462                 error(1, 0, "setsockopt timestamping");
 463 
 464         for (i = 0; i < cfg_num_pkts; i++) {
 465                 memset(&msg, 0, sizeof(msg));
 466                 memset(buf, 'a' + i, total_len);
 467 
 468                 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) {
 469                         int off = 0;
 470 
 471                         if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) {
 472                                 if (family == PF_INET)
 473                                         off = fill_header_ipv4(buf);
 474                                 else
 475                                         off = fill_header_ipv6(buf);
 476                         }
 477 
 478                         fill_header_udp(buf + off, family == PF_INET);
 479                 }
 480 
 481                 print_timestamp_usr();
 482 
 483                 iov.iov_base = buf;
 484                 iov.iov_len = total_len;
 485 
 486                 if (cfg_proto != SOCK_STREAM) {
 487                         if (cfg_use_pf_packet) {
 488                                 memset(&laddr, 0, sizeof(laddr));
 489 
 490                                 laddr.sll_family        = AF_PACKET;
 491                                 laddr.sll_ifindex       = 1;
 492                                 laddr.sll_protocol      = htons(family == AF_INET ? ETH_P_IP : ETH_P_IPV6);
 493                                 laddr.sll_halen         = ETH_ALEN;
 494 
 495                                 msg.msg_name = (void *)&laddr;
 496                                 msg.msg_namelen = sizeof(laddr);
 497                         } else if (family == PF_INET) {
 498                                 msg.msg_name = (void *)&daddr;
 499                                 msg.msg_namelen = sizeof(daddr);
 500                         } else {
 501                                 msg.msg_name = (void *)&daddr6;
 502                                 msg.msg_namelen = sizeof(daddr6);
 503                         }
 504                 }
 505 
 506                 msg.msg_iov = &iov;
 507                 msg.msg_iovlen = 1;
 508 
 509                 if (cfg_use_cmsg) {
 510                         memset(control, 0, sizeof(control));
 511 
 512                         msg.msg_control = control;
 513                         msg.msg_controllen = sizeof(control);
 514 
 515                         cmsg = CMSG_FIRSTHDR(&msg);
 516                         cmsg->cmsg_level = SOL_SOCKET;
 517                         cmsg->cmsg_type = SO_TIMESTAMPING;
 518                         cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
 519 
 520                         *((uint32_t *) CMSG_DATA(cmsg)) = report_opt;
 521                 }
 522 
 523                 val = sendmsg(fd, &msg, 0);
 524                 if (val != total_len)
 525                         error(1, errno, "send");
 526 
 527                 /* wait for all errors to be queued, else ACKs arrive OOO */
 528                 if (!cfg_no_delay)
 529                         usleep(50 * 1000);
 530 
 531                 __poll(fd);
 532 
 533                 while (!recv_errmsg(fd)) {}
 534         }
 535 
 536         if (close(fd))
 537                 error(1, errno, "close");
 538 
 539         free(buf);
 540         usleep(100 * 1000);
 541 }
 542 
 543 static void __attribute__((noreturn)) usage(const char *filepath)
 544 {
 545         fprintf(stderr, "\nUsage: %s [options] hostname\n"
 546                         "\nwhere options are:\n"
 547                         "  -4:   only IPv4\n"
 548                         "  -6:   only IPv6\n"
 549                         "  -h:   show this message\n"
 550                         "  -c N: number of packets for each test\n"
 551                         "  -C:   use cmsg to set tstamp recording options\n"
 552                         "  -D:   no delay between packets\n"
 553                         "  -F:   poll() waits forever for an event\n"
 554                         "  -I:   request PKTINFO\n"
 555                         "  -l N: send N bytes at a time\n"
 556                         "  -L    listen on hostname and port\n"
 557                         "  -n:   set no-payload option\n"
 558                         "  -p N: connect to port N\n"
 559                         "  -P:   use PF_PACKET\n"
 560                         "  -r:   use raw\n"
 561                         "  -R:   use raw (IP_HDRINCL)\n"
 562                         "  -u:   use udp\n"
 563                         "  -v:   validate SND delay (usec)\n"
 564                         "  -V:   validate ACK delay (usec)\n"
 565                         "  -x:   show payload (up to 70 bytes)\n",
 566                         filepath);
 567         exit(1);
 568 }
 569 
 570 static void parse_opt(int argc, char **argv)
 571 {
 572         int proto_count = 0;
 573         int c;
 574 
 575         while ((c = getopt(argc, argv, "46c:CDFhIl:Lnp:PrRuv:V:x")) != -1) {
 576                 switch (c) {
 577                 case '4':
 578                         do_ipv6 = 0;
 579                         break;
 580                 case '6':
 581                         do_ipv4 = 0;
 582                         break;
 583                 case 'c':
 584                         cfg_num_pkts = strtoul(optarg, NULL, 10);
 585                         break;
 586                 case 'C':
 587                         cfg_use_cmsg = true;
 588                         break;
 589                 case 'D':
 590                         cfg_no_delay = true;
 591                         break;
 592                 case 'F':
 593                         cfg_poll_timeout = -1;
 594                         break;
 595                 case 'I':
 596                         cfg_do_pktinfo = true;
 597                         break;
 598                 case 'l':
 599                         cfg_payload_len = strtoul(optarg, NULL, 10);
 600                         break;
 601                 case 'L':
 602                         cfg_do_listen = true;
 603                         break;
 604                 case 'n':
 605                         cfg_loop_nodata = true;
 606                         break;
 607                 case 'p':
 608                         dest_port = strtoul(optarg, NULL, 10);
 609                         break;
 610                 case 'P':
 611                         proto_count++;
 612                         cfg_use_pf_packet = true;
 613                         cfg_proto = SOCK_DGRAM;
 614                         cfg_ipproto = 0;
 615                         break;
 616                 case 'r':
 617                         proto_count++;
 618                         cfg_proto = SOCK_RAW;
 619                         cfg_ipproto = IPPROTO_UDP;
 620                         break;
 621                 case 'R':
 622                         proto_count++;
 623                         cfg_proto = SOCK_RAW;
 624                         cfg_ipproto = IPPROTO_RAW;
 625                         break;
 626                 case 'u':
 627                         proto_count++;
 628                         cfg_proto = SOCK_DGRAM;
 629                         cfg_ipproto = IPPROTO_UDP;
 630                         break;
 631                 case 'v':
 632                         cfg_delay_snd = strtoul(optarg, NULL, 10);
 633                         break;
 634                 case 'V':
 635                         cfg_delay_ack = strtoul(optarg, NULL, 10);
 636                         break;
 637                 case 'x':
 638                         cfg_show_payload = true;
 639                         break;
 640                 case 'h':
 641                 default:
 642                         usage(argv[0]);
 643                 }
 644         }
 645 
 646         if (!cfg_payload_len)
 647                 error(1, 0, "payload may not be nonzero");
 648         if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
 649                 error(1, 0, "udp packet might exceed expected MTU");
 650         if (!do_ipv4 && !do_ipv6)
 651                 error(1, 0, "pass -4 or -6, not both");
 652         if (proto_count > 1)
 653                 error(1, 0, "pass -P, -r, -R or -u, not multiple");
 654         if (cfg_do_pktinfo && cfg_use_pf_packet)
 655                 error(1, 0, "cannot ask for pktinfo over pf_packet");
 656 
 657         if (optind != argc - 1)
 658                 error(1, 0, "missing required hostname argument");
 659 }
 660 
 661 static void resolve_hostname(const char *hostname)
 662 {
 663         struct addrinfo hints = { .ai_family = do_ipv4 ? AF_INET : AF_INET6 };
 664         struct addrinfo *addrs, *cur;
 665         int have_ipv4 = 0, have_ipv6 = 0;
 666 
 667 retry:
 668         if (getaddrinfo(hostname, NULL, &hints, &addrs))
 669                 error(1, errno, "getaddrinfo");
 670 
 671         cur = addrs;
 672         while (cur && !have_ipv4 && !have_ipv6) {
 673                 if (!have_ipv4 && cur->ai_family == AF_INET) {
 674                         memcpy(&daddr, cur->ai_addr, sizeof(daddr));
 675                         daddr.sin_port = htons(dest_port);
 676                         have_ipv4 = 1;
 677                 }
 678                 else if (!have_ipv6 && cur->ai_family == AF_INET6) {
 679                         memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
 680                         daddr6.sin6_port = htons(dest_port);
 681                         have_ipv6 = 1;
 682                 }
 683                 cur = cur->ai_next;
 684         }
 685         if (addrs)
 686                 freeaddrinfo(addrs);
 687 
 688         if (do_ipv6 && hints.ai_family != AF_INET6) {
 689                 hints.ai_family = AF_INET6;
 690                 goto retry;
 691         }
 692 
 693         do_ipv4 &= have_ipv4;
 694         do_ipv6 &= have_ipv6;
 695 }
 696 
 697 static void do_listen(int family, void *addr, int alen)
 698 {
 699         int fd, type;
 700 
 701         type = cfg_proto == SOCK_RAW ? SOCK_DGRAM : cfg_proto;
 702 
 703         fd = socket(family, type, 0);
 704         if (fd == -1)
 705                 error(1, errno, "socket rx");
 706 
 707         if (bind(fd, addr, alen))
 708                 error(1, errno, "bind rx");
 709 
 710         if (type == SOCK_STREAM && listen(fd, 10))
 711                 error(1, errno, "listen rx");
 712 
 713         /* leave fd open, will be closed on process exit.
 714          * this enables connect() to succeed and avoids icmp replies
 715          */
 716 }
 717 
 718 static void do_main(int family)
 719 {
 720         fprintf(stderr, "family:       %s %s\n",
 721                         family == PF_INET ? "INET" : "INET6",
 722                         cfg_use_pf_packet ? "(PF_PACKET)" : "");
 723 
 724         fprintf(stderr, "test SND\n");
 725         do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
 726 
 727         fprintf(stderr, "test ENQ\n");
 728         do_test(family, SOF_TIMESTAMPING_TX_SCHED);
 729 
 730         fprintf(stderr, "test ENQ + SND\n");
 731         do_test(family, SOF_TIMESTAMPING_TX_SCHED |
 732                         SOF_TIMESTAMPING_TX_SOFTWARE);
 733 
 734         if (cfg_proto == SOCK_STREAM) {
 735                 fprintf(stderr, "\ntest ACK\n");
 736                 do_test(family, SOF_TIMESTAMPING_TX_ACK);
 737 
 738                 fprintf(stderr, "\ntest SND + ACK\n");
 739                 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
 740                                 SOF_TIMESTAMPING_TX_ACK);
 741 
 742                 fprintf(stderr, "\ntest ENQ + SND + ACK\n");
 743                 do_test(family, SOF_TIMESTAMPING_TX_SCHED |
 744                                 SOF_TIMESTAMPING_TX_SOFTWARE |
 745                                 SOF_TIMESTAMPING_TX_ACK);
 746         }
 747 }
 748 
 749 const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
 750 
 751 int main(int argc, char **argv)
 752 {
 753         if (argc == 1)
 754                 usage(argv[0]);
 755 
 756         parse_opt(argc, argv);
 757         resolve_hostname(argv[argc - 1]);
 758 
 759         fprintf(stderr, "protocol:     %s\n", sock_names[cfg_proto]);
 760         fprintf(stderr, "payload:      %u\n", cfg_payload_len);
 761         fprintf(stderr, "server port:  %u\n", dest_port);
 762         fprintf(stderr, "\n");
 763 
 764         if (do_ipv4) {
 765                 if (cfg_do_listen)
 766                         do_listen(PF_INET, &daddr, sizeof(daddr));
 767                 do_main(PF_INET);
 768         }
 769 
 770         if (do_ipv6) {
 771                 if (cfg_do_listen)
 772                         do_listen(PF_INET6, &daddr6, sizeof(daddr6));
 773                 do_main(PF_INET6);
 774         }
 775 
 776         return test_failed;
 777 }

/* [<][>][^][v][top][bottom][index][help] */