]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Dec 2018 09:50:49 +0000 (10:50 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Dec 2018 09:50:49 +0000 (10:50 +0100)
added patches:
rocker-fix-rocker_tlv_put_-functions-for-kasan.patch
selftests-move-networking-timestamping-from-documentation.patch

queue-4.4/rocker-fix-rocker_tlv_put_-functions-for-kasan.patch [new file with mode: 0644]
queue-4.4/selftests-move-networking-timestamping-from-documentation.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/rocker-fix-rocker_tlv_put_-functions-for-kasan.patch b/queue-4.4/rocker-fix-rocker_tlv_put_-functions-for-kasan.patch
new file mode 100644 (file)
index 0000000..0876865
--- /dev/null
@@ -0,0 +1,88 @@
+From 6098d7ddd62f532f80ee2a4b01aca500a8e4e9e4 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Fri, 22 Sep 2017 23:29:18 +0200
+Subject: rocker: fix rocker_tlv_put_* functions for KASAN
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+commit 6098d7ddd62f532f80ee2a4b01aca500a8e4e9e4 upstream.
+
+Inlining these functions creates lots of stack variables that each take
+64 bytes when KASAN is enabled, leading to this warning about potential
+stack overflow:
+
+drivers/net/ethernet/rocker/rocker_ofdpa.c: In function 'ofdpa_cmd_flow_tbl_add':
+drivers/net/ethernet/rocker/rocker_ofdpa.c:621:1: error: the frame size of 2752 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]
+
+gcc-8 can now consolidate the stack slots itself, but on older versions
+we get the same behavior by using a temporary variable that holds a
+copy of the inline function argument.
+
+Cc: stable@vger.kernel.org
+Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/rocker/rocker.c |   24 ++++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/rocker/rocker.c
++++ b/drivers/net/ethernet/rocker/rocker.c
+@@ -821,37 +821,49 @@ static int rocker_tlv_put(struct rocker_
+ static int rocker_tlv_put_u8(struct rocker_desc_info *desc_info,
+                            int attrtype, u8 value)
+ {
+-      return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &value);
++      u8 tmp = value; /* work around GCC PR81715 */
++
++      return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &tmp);
+ }
+ static int rocker_tlv_put_u16(struct rocker_desc_info *desc_info,
+                             int attrtype, u16 value)
+ {
+-      return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &value);
++      u16 tmp = value;
++
++      return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &tmp);
+ }
+ static int rocker_tlv_put_be16(struct rocker_desc_info *desc_info,
+                              int attrtype, __be16 value)
+ {
+-      return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &value);
++      __be16 tmp = value;
++
++      return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &tmp);
+ }
+ static int rocker_tlv_put_u32(struct rocker_desc_info *desc_info,
+                             int attrtype, u32 value)
+ {
+-      return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &value);
++      u32 tmp = value;
++
++      return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &tmp);
+ }
+ static int rocker_tlv_put_be32(struct rocker_desc_info *desc_info,
+                              int attrtype, __be32 value)
+ {
+-      return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &value);
++      __be32 tmp = value;
++
++      return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &tmp);
+ }
+ static int rocker_tlv_put_u64(struct rocker_desc_info *desc_info,
+                             int attrtype, u64 value)
+ {
+-      return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &value);
++      u64 tmp = value;
++
++      return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &tmp);
+ }
+ static struct rocker_tlv *
diff --git a/queue-4.4/selftests-move-networking-timestamping-from-documentation.patch b/queue-4.4/selftests-move-networking-timestamping-from-documentation.patch
new file mode 100644 (file)
index 0000000..8c5a516
--- /dev/null
@@ -0,0 +1,2529 @@
+From 3d2c86e3057995270e08693231039d9d942871f0 Mon Sep 17 00:00:00 2001
+From: Shuah Khan <shuahkh@osg.samsung.com>
+Date: Thu, 15 Sep 2016 08:36:07 -0600
+Subject: selftests: Move networking/timestamping from Documentation
+
+From: Shuah Khan <shuahkh@osg.samsung.com>
+
+commit 3d2c86e3057995270e08693231039d9d942871f0 upstream.
+
+Remove networking from Documentation Makefile to move the test to
+selftests. Update networking/timestamping Makefile to work under
+selftests. These tests will not be run as part of selftests suite
+and will not be included in install targets. They can be built and
+run separately for now.
+
+This is part of the effort to move runnable code from Documentation.
+
+Acked-by: Jonathan Corbet <corbet@lwn.net>
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+[ added to 4.4.y stable to remove a build warning - gregkh]
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ Documentation/Makefile                                            |    3 
+ Documentation/networking/Makefile                                 |    1 
+ Documentation/networking/timestamping/.gitignore                  |    3 
+ Documentation/networking/timestamping/Makefile                    |   14 
+ Documentation/networking/timestamping/hwtstamp_config.c           |  134 --
+ Documentation/networking/timestamping/timestamping.c              |  528 ---------
+ Documentation/networking/timestamping/txtimestamp.c               |  549 ----------
+ tools/testing/selftests/networking/timestamping/.gitignore        |    3 
+ tools/testing/selftests/networking/timestamping/Makefile          |    8 
+ tools/testing/selftests/networking/timestamping/hwtstamp_config.c |  134 ++
+ tools/testing/selftests/networking/timestamping/timestamping.c    |  528 +++++++++
+ tools/testing/selftests/networking/timestamping/txtimestamp.c     |  549 ++++++++++
+ 12 files changed, 1223 insertions(+), 1231 deletions(-)
+
+--- a/Documentation/Makefile
++++ b/Documentation/Makefile
+@@ -1,4 +1,3 @@
+ subdir-y := accounting auxdisplay blackfin connector \
+       filesystems filesystems ia64 laptops misc-devices \
+-      networking pcmcia prctl ptp spi timers vDSO video4linux \
+-      watchdog
++      pcmcia prctl ptp spi timers vDSO video4linux watchdog
+--- a/Documentation/networking/Makefile
++++ /dev/null
+@@ -1 +0,0 @@
+-subdir-y := timestamping
+--- a/Documentation/networking/timestamping/.gitignore
++++ /dev/null
+@@ -1,3 +0,0 @@
+-timestamping
+-txtimestamp
+-hwtstamp_config
+--- a/Documentation/networking/timestamping/Makefile
++++ /dev/null
+@@ -1,14 +0,0 @@
+-# To compile, from the source root
+-#
+-#    make headers_install
+-#    make M=documentation
+-
+-# List of programs to build
+-hostprogs-y := hwtstamp_config timestamping txtimestamp
+-
+-# Tell kbuild to always build the programs
+-always := $(hostprogs-y)
+-
+-HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include
+-HOSTCFLAGS_txtimestamp.o += -I$(objtree)/usr/include
+-HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include
+--- a/Documentation/networking/timestamping/hwtstamp_config.c
++++ /dev/null
+@@ -1,134 +0,0 @@
+-/* Test program for SIOC{G,S}HWTSTAMP
+- * Copyright 2013 Solarflare Communications
+- * Author: Ben Hutchings
+- */
+-
+-#include <errno.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-
+-#include <sys/socket.h>
+-#include <sys/ioctl.h>
+-
+-#include <linux/if.h>
+-#include <linux/net_tstamp.h>
+-#include <linux/sockios.h>
+-
+-static int
+-lookup_value(const char **names, int size, const char *name)
+-{
+-      int value;
+-
+-      for (value = 0; value < size; value++)
+-              if (names[value] && strcasecmp(names[value], name) == 0)
+-                      return value;
+-
+-      return -1;
+-}
+-
+-static const char *
+-lookup_name(const char **names, int size, int value)
+-{
+-      return (value >= 0 && value < size) ? names[value] : NULL;
+-}
+-
+-static void list_names(FILE *f, const char **names, int size)
+-{
+-      int value;
+-
+-      for (value = 0; value < size; value++)
+-              if (names[value])
+-                      fprintf(f, "    %s\n", names[value]);
+-}
+-
+-static const char *tx_types[] = {
+-#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name
+-      TX_TYPE(OFF),
+-      TX_TYPE(ON),
+-      TX_TYPE(ONESTEP_SYNC)
+-#undef TX_TYPE
+-};
+-#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0])))
+-
+-static const char *rx_filters[] = {
+-#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name
+-      RX_FILTER(NONE),
+-      RX_FILTER(ALL),
+-      RX_FILTER(SOME),
+-      RX_FILTER(PTP_V1_L4_EVENT),
+-      RX_FILTER(PTP_V1_L4_SYNC),
+-      RX_FILTER(PTP_V1_L4_DELAY_REQ),
+-      RX_FILTER(PTP_V2_L4_EVENT),
+-      RX_FILTER(PTP_V2_L4_SYNC),
+-      RX_FILTER(PTP_V2_L4_DELAY_REQ),
+-      RX_FILTER(PTP_V2_L2_EVENT),
+-      RX_FILTER(PTP_V2_L2_SYNC),
+-      RX_FILTER(PTP_V2_L2_DELAY_REQ),
+-      RX_FILTER(PTP_V2_EVENT),
+-      RX_FILTER(PTP_V2_SYNC),
+-      RX_FILTER(PTP_V2_DELAY_REQ),
+-#undef RX_FILTER
+-};
+-#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0])))
+-
+-static void usage(void)
+-{
+-      fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n"
+-            "tx_type is any of (case-insensitive):\n",
+-            stderr);
+-      list_names(stderr, tx_types, N_TX_TYPES);
+-      fputs("rx_filter is any of (case-insensitive):\n", stderr);
+-      list_names(stderr, rx_filters, N_RX_FILTERS);
+-}
+-
+-int main(int argc, char **argv)
+-{
+-      struct ifreq ifr;
+-      struct hwtstamp_config config;
+-      const char *name;
+-      int sock;
+-
+-      if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) {
+-              usage();
+-              return 2;
+-      }
+-
+-      if (argc == 4) {
+-              config.flags = 0;
+-              config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]);
+-              config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]);
+-              if (config.tx_type < 0 || config.rx_filter < 0) {
+-                      usage();
+-                      return 2;
+-              }
+-      }
+-
+-      sock = socket(AF_INET, SOCK_DGRAM, 0);
+-      if (sock < 0) {
+-              perror("socket");
+-              return 1;
+-      }
+-
+-      strcpy(ifr.ifr_name, argv[1]);
+-      ifr.ifr_data = (caddr_t)&config;
+-
+-      if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) {
+-              perror("ioctl");
+-              return 1;
+-      }
+-
+-      printf("flags = %#x\n", config.flags);
+-      name = lookup_name(tx_types, N_TX_TYPES, config.tx_type);
+-      if (name)
+-              printf("tx_type = %s\n", name);
+-      else
+-              printf("tx_type = %d\n", config.tx_type);
+-      name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter);
+-      if (name)
+-              printf("rx_filter = %s\n", name);
+-      else
+-              printf("rx_filter = %d\n", config.rx_filter);
+-
+-      return 0;
+-}
+--- a/Documentation/networking/timestamping/timestamping.c
++++ /dev/null
+@@ -1,528 +0,0 @@
+-/*
+- * This program demonstrates how the various time stamping features in
+- * the Linux kernel work. It emulates the behavior of a PTP
+- * implementation in stand-alone master mode by sending PTPv1 Sync
+- * multicasts once every second. It looks for similar packets, but
+- * beyond that doesn't actually implement PTP.
+- *
+- * Outgoing packets are time stamped with SO_TIMESTAMPING with or
+- * without hardware support.
+- *
+- * Incoming packets are time stamped with SO_TIMESTAMPING with or
+- * without hardware support, SIOCGSTAMP[NS] (per-socket time stamp) and
+- * SO_TIMESTAMP[NS].
+- *
+- * Copyright (C) 2009 Intel Corporation.
+- * Author: Patrick Ohly <patrick.ohly@intel.com>
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms and conditions of the GNU General Public License,
+- * version 2, as published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
+- * more details.
+- *
+- * You should have received a copy of the GNU General Public License along with
+- * this program; if not, write to the Free Software Foundation, Inc.,
+- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <errno.h>
+-#include <string.h>
+-
+-#include <sys/time.h>
+-#include <sys/socket.h>
+-#include <sys/select.h>
+-#include <sys/ioctl.h>
+-#include <arpa/inet.h>
+-#include <net/if.h>
+-
+-#include <asm/types.h>
+-#include <linux/net_tstamp.h>
+-#include <linux/errqueue.h>
+-
+-#ifndef SO_TIMESTAMPING
+-# define SO_TIMESTAMPING         37
+-# define SCM_TIMESTAMPING        SO_TIMESTAMPING
+-#endif
+-
+-#ifndef SO_TIMESTAMPNS
+-# define SO_TIMESTAMPNS 35
+-#endif
+-
+-#ifndef SIOCGSTAMPNS
+-# define SIOCGSTAMPNS 0x8907
+-#endif
+-
+-#ifndef SIOCSHWTSTAMP
+-# define SIOCSHWTSTAMP 0x89b0
+-#endif
+-
+-static void usage(const char *error)
+-{
+-      if (error)
+-              printf("invalid option: %s\n", error);
+-      printf("timestamping interface option*\n\n"
+-             "Options:\n"
+-             "  IP_MULTICAST_LOOP - looping outgoing multicasts\n"
+-             "  SO_TIMESTAMP - normal software time stamping, ms resolution\n"
+-             "  SO_TIMESTAMPNS - more accurate software time stamping\n"
+-             "  SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n"
+-             "  SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n"
+-             "  SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n"
+-             "  SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n"
+-             "  SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n"
+-             "  SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
+-             "  SIOCGSTAMP - check last socket time stamp\n"
+-             "  SIOCGSTAMPNS - more accurate socket time stamp\n");
+-      exit(1);
+-}
+-
+-static void bail(const char *error)
+-{
+-      printf("%s: %s\n", error, strerror(errno));
+-      exit(1);
+-}
+-
+-static const unsigned char sync[] = {
+-      0x00, 0x01, 0x00, 0x01,
+-      0x5f, 0x44, 0x46, 0x4c,
+-      0x54, 0x00, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x01, 0x01,
+-
+-      /* fake uuid */
+-      0x00, 0x01,
+-      0x02, 0x03, 0x04, 0x05,
+-
+-      0x00, 0x01, 0x00, 0x37,
+-      0x00, 0x00, 0x00, 0x08,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x49, 0x05, 0xcd, 0x01,
+-      0x29, 0xb1, 0x8d, 0xb0,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x00, 0x01,
+-
+-      /* fake uuid */
+-      0x00, 0x01,
+-      0x02, 0x03, 0x04, 0x05,
+-
+-      0x00, 0x00, 0x00, 0x37,
+-      0x00, 0x00, 0x00, 0x04,
+-      0x44, 0x46, 0x4c, 0x54,
+-      0x00, 0x00, 0xf0, 0x60,
+-      0x00, 0x01, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x01,
+-      0x00, 0x00, 0xf0, 0x60,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x04,
+-      0x44, 0x46, 0x4c, 0x54,
+-      0x00, 0x01,
+-
+-      /* fake uuid */
+-      0x00, 0x01,
+-      0x02, 0x03, 0x04, 0x05,
+-
+-      0x00, 0x00, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x00,
+-      0x00, 0x00, 0x00, 0x00
+-};
+-
+-static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len)
+-{
+-      struct timeval now;
+-      int res;
+-
+-      res = sendto(sock, sync, sizeof(sync), 0,
+-              addr, addr_len);
+-      gettimeofday(&now, 0);
+-      if (res < 0)
+-              printf("%s: %s\n", "send", strerror(errno));
+-      else
+-              printf("%ld.%06ld: sent %d bytes\n",
+-                     (long)now.tv_sec, (long)now.tv_usec,
+-                     res);
+-}
+-
+-static void printpacket(struct msghdr *msg, int res,
+-                      char *data,
+-                      int sock, int recvmsg_flags,
+-                      int siocgstamp, int siocgstampns)
+-{
+-      struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
+-      struct cmsghdr *cmsg;
+-      struct timeval tv;
+-      struct timespec ts;
+-      struct timeval now;
+-
+-      gettimeofday(&now, 0);
+-
+-      printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
+-             (long)now.tv_sec, (long)now.tv_usec,
+-             (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
+-             res,
+-             inet_ntoa(from_addr->sin_addr),
+-             msg->msg_controllen);
+-      for (cmsg = CMSG_FIRSTHDR(msg);
+-           cmsg;
+-           cmsg = CMSG_NXTHDR(msg, cmsg)) {
+-              printf("   cmsg len %zu: ", cmsg->cmsg_len);
+-              switch (cmsg->cmsg_level) {
+-              case SOL_SOCKET:
+-                      printf("SOL_SOCKET ");
+-                      switch (cmsg->cmsg_type) {
+-                      case SO_TIMESTAMP: {
+-                              struct timeval *stamp =
+-                                      (struct timeval *)CMSG_DATA(cmsg);
+-                              printf("SO_TIMESTAMP %ld.%06ld",
+-                                     (long)stamp->tv_sec,
+-                                     (long)stamp->tv_usec);
+-                              break;
+-                      }
+-                      case SO_TIMESTAMPNS: {
+-                              struct timespec *stamp =
+-                                      (struct timespec *)CMSG_DATA(cmsg);
+-                              printf("SO_TIMESTAMPNS %ld.%09ld",
+-                                     (long)stamp->tv_sec,
+-                                     (long)stamp->tv_nsec);
+-                              break;
+-                      }
+-                      case SO_TIMESTAMPING: {
+-                              struct timespec *stamp =
+-                                      (struct timespec *)CMSG_DATA(cmsg);
+-                              printf("SO_TIMESTAMPING ");
+-                              printf("SW %ld.%09ld ",
+-                                     (long)stamp->tv_sec,
+-                                     (long)stamp->tv_nsec);
+-                              stamp++;
+-                              /* skip deprecated HW transformed */
+-                              stamp++;
+-                              printf("HW raw %ld.%09ld",
+-                                     (long)stamp->tv_sec,
+-                                     (long)stamp->tv_nsec);
+-                              break;
+-                      }
+-                      default:
+-                              printf("type %d", cmsg->cmsg_type);
+-                              break;
+-                      }
+-                      break;
+-              case IPPROTO_IP:
+-                      printf("IPPROTO_IP ");
+-                      switch (cmsg->cmsg_type) {
+-                      case IP_RECVERR: {
+-                              struct sock_extended_err *err =
+-                                      (struct sock_extended_err *)CMSG_DATA(cmsg);
+-                              printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s",
+-                                      strerror(err->ee_errno),
+-                                      err->ee_origin,
+-#ifdef SO_EE_ORIGIN_TIMESTAMPING
+-                                      err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ?
+-                                      "bounced packet" : "unexpected origin"
+-#else
+-                                      "probably SO_EE_ORIGIN_TIMESTAMPING"
+-#endif
+-                                      );
+-                              if (res < sizeof(sync))
+-                                      printf(" => truncated data?!");
+-                              else if (!memcmp(sync, data + res - sizeof(sync),
+-                                                      sizeof(sync)))
+-                                      printf(" => GOT OUR DATA BACK (HURRAY!)");
+-                              break;
+-                      }
+-                      case IP_PKTINFO: {
+-                              struct in_pktinfo *pktinfo =
+-                                      (struct in_pktinfo *)CMSG_DATA(cmsg);
+-                              printf("IP_PKTINFO interface index %u",
+-                                      pktinfo->ipi_ifindex);
+-                              break;
+-                      }
+-                      default:
+-                              printf("type %d", cmsg->cmsg_type);
+-                              break;
+-                      }
+-                      break;
+-              default:
+-                      printf("level %d type %d",
+-                              cmsg->cmsg_level,
+-                              cmsg->cmsg_type);
+-                      break;
+-              }
+-              printf("\n");
+-      }
+-
+-      if (siocgstamp) {
+-              if (ioctl(sock, SIOCGSTAMP, &tv))
+-                      printf("   %s: %s\n", "SIOCGSTAMP", strerror(errno));
+-              else
+-                      printf("SIOCGSTAMP %ld.%06ld\n",
+-                             (long)tv.tv_sec,
+-                             (long)tv.tv_usec);
+-      }
+-      if (siocgstampns) {
+-              if (ioctl(sock, SIOCGSTAMPNS, &ts))
+-                      printf("   %s: %s\n", "SIOCGSTAMPNS", strerror(errno));
+-              else
+-                      printf("SIOCGSTAMPNS %ld.%09ld\n",
+-                             (long)ts.tv_sec,
+-                             (long)ts.tv_nsec);
+-      }
+-}
+-
+-static void recvpacket(int sock, int recvmsg_flags,
+-                     int siocgstamp, int siocgstampns)
+-{
+-      char data[256];
+-      struct msghdr msg;
+-      struct iovec entry;
+-      struct sockaddr_in from_addr;
+-      struct {
+-              struct cmsghdr cm;
+-              char control[512];
+-      } control;
+-      int res;
+-
+-      memset(&msg, 0, sizeof(msg));
+-      msg.msg_iov = &entry;
+-      msg.msg_iovlen = 1;
+-      entry.iov_base = data;
+-      entry.iov_len = sizeof(data);
+-      msg.msg_name = (caddr_t)&from_addr;
+-      msg.msg_namelen = sizeof(from_addr);
+-      msg.msg_control = &control;
+-      msg.msg_controllen = sizeof(control);
+-
+-      res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
+-      if (res < 0) {
+-              printf("%s %s: %s\n",
+-                     "recvmsg",
+-                     (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
+-                     strerror(errno));
+-      } else {
+-              printpacket(&msg, res, data,
+-                          sock, recvmsg_flags,
+-                          siocgstamp, siocgstampns);
+-      }
+-}
+-
+-int main(int argc, char **argv)
+-{
+-      int so_timestamping_flags = 0;
+-      int so_timestamp = 0;
+-      int so_timestampns = 0;
+-      int siocgstamp = 0;
+-      int siocgstampns = 0;
+-      int ip_multicast_loop = 0;
+-      char *interface;
+-      int i;
+-      int enabled = 1;
+-      int sock;
+-      struct ifreq device;
+-      struct ifreq hwtstamp;
+-      struct hwtstamp_config hwconfig, hwconfig_requested;
+-      struct sockaddr_in addr;
+-      struct ip_mreq imr;
+-      struct in_addr iaddr;
+-      int val;
+-      socklen_t len;
+-      struct timeval next;
+-
+-      if (argc < 2)
+-              usage(0);
+-      interface = argv[1];
+-
+-      for (i = 2; i < argc; i++) {
+-              if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
+-                      so_timestamp = 1;
+-              else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
+-                      so_timestampns = 1;
+-              else if (!strcasecmp(argv[i], "SIOCGSTAMP"))
+-                      siocgstamp = 1;
+-              else if (!strcasecmp(argv[i], "SIOCGSTAMPNS"))
+-                      siocgstampns = 1;
+-              else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP"))
+-                      ip_multicast_loop = 1;
+-              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE"))
+-                      so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
+-              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE"))
+-                      so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
+-              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE"))
+-                      so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE;
+-              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE"))
+-                      so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
+-              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE"))
+-                      so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE;
+-              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE"))
+-                      so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
+-              else
+-                      usage(argv[i]);
+-      }
+-
+-      sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+-      if (sock < 0)
+-              bail("socket");
+-
+-      memset(&device, 0, sizeof(device));
+-      strncpy(device.ifr_name, interface, sizeof(device.ifr_name));
+-      if (ioctl(sock, SIOCGIFADDR, &device) < 0)
+-              bail("getting interface IP address");
+-
+-      memset(&hwtstamp, 0, sizeof(hwtstamp));
+-      strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name));
+-      hwtstamp.ifr_data = (void *)&hwconfig;
+-      memset(&hwconfig, 0, sizeof(hwconfig));
+-      hwconfig.tx_type =
+-              (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ?
+-              HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+-      hwconfig.rx_filter =
+-              (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ?
+-              HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE;
+-      hwconfig_requested = hwconfig;
+-      if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) {
+-              if ((errno == EINVAL || errno == ENOTSUP) &&
+-                  hwconfig_requested.tx_type == HWTSTAMP_TX_OFF &&
+-                  hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE)
+-                      printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
+-              else
+-                      bail("SIOCSHWTSTAMP");
+-      }
+-      printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
+-             hwconfig_requested.tx_type, hwconfig.tx_type,
+-             hwconfig_requested.rx_filter, hwconfig.rx_filter);
+-
+-      /* bind to PTP port */
+-      addr.sin_family = AF_INET;
+-      addr.sin_addr.s_addr = htonl(INADDR_ANY);
+-      addr.sin_port = htons(319 /* PTP event port */);
+-      if (bind(sock,
+-               (struct sockaddr *)&addr,
+-               sizeof(struct sockaddr_in)) < 0)
+-              bail("bind");
+-
+-      /* set multicast group for outgoing packets */
+-      inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
+-      addr.sin_addr = iaddr;
+-      imr.imr_multiaddr.s_addr = iaddr.s_addr;
+-      imr.imr_interface.s_addr =
+-              ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
+-      if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
+-                     &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
+-              bail("set multicast");
+-
+-      /* join multicast group, loop our own packet */
+-      if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+-                     &imr, sizeof(struct ip_mreq)) < 0)
+-              bail("join multicast group");
+-
+-      if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
+-                     &ip_multicast_loop, sizeof(enabled)) < 0) {
+-              bail("loop multicast");
+-      }
+-
+-      /* set socket options for time stamping */
+-      if (so_timestamp &&
+-              setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
+-                         &enabled, sizeof(enabled)) < 0)
+-              bail("setsockopt SO_TIMESTAMP");
+-
+-      if (so_timestampns &&
+-              setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
+-                         &enabled, sizeof(enabled)) < 0)
+-              bail("setsockopt SO_TIMESTAMPNS");
+-
+-      if (so_timestamping_flags &&
+-              setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,
+-                         &so_timestamping_flags,
+-                         sizeof(so_timestamping_flags)) < 0)
+-              bail("setsockopt SO_TIMESTAMPING");
+-
+-      /* request IP_PKTINFO for debugging purposes */
+-      if (setsockopt(sock, SOL_IP, IP_PKTINFO,
+-                     &enabled, sizeof(enabled)) < 0)
+-              printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno));
+-
+-      /* verify socket options */
+-      len = sizeof(val);
+-      if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
+-              printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
+-      else
+-              printf("SO_TIMESTAMP %d\n", val);
+-
+-      if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
+-              printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS",
+-                     strerror(errno));
+-      else
+-              printf("SO_TIMESTAMPNS %d\n", val);
+-
+-      if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) {
+-              printf("%s: %s\n", "getsockopt SO_TIMESTAMPING",
+-                     strerror(errno));
+-      } else {
+-              printf("SO_TIMESTAMPING %d\n", val);
+-              if (val != so_timestamping_flags)
+-                      printf("   not the expected value %d\n",
+-                             so_timestamping_flags);
+-      }
+-
+-      /* send packets forever every five seconds */
+-      gettimeofday(&next, 0);
+-      next.tv_sec = (next.tv_sec + 1) / 5 * 5;
+-      next.tv_usec = 0;
+-      while (1) {
+-              struct timeval now;
+-              struct timeval delta;
+-              long delta_us;
+-              int res;
+-              fd_set readfs, errorfs;
+-
+-              gettimeofday(&now, 0);
+-              delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
+-                      (long)(next.tv_usec - now.tv_usec);
+-              if (delta_us > 0) {
+-                      /* continue waiting for timeout or data */
+-                      delta.tv_sec = delta_us / 1000000;
+-                      delta.tv_usec = delta_us % 1000000;
+-
+-                      FD_ZERO(&readfs);
+-                      FD_ZERO(&errorfs);
+-                      FD_SET(sock, &readfs);
+-                      FD_SET(sock, &errorfs);
+-                      printf("%ld.%06ld: select %ldus\n",
+-                             (long)now.tv_sec, (long)now.tv_usec,
+-                             delta_us);
+-                      res = select(sock + 1, &readfs, 0, &errorfs, &delta);
+-                      gettimeofday(&now, 0);
+-                      printf("%ld.%06ld: select returned: %d, %s\n",
+-                             (long)now.tv_sec, (long)now.tv_usec,
+-                             res,
+-                             res < 0 ? strerror(errno) : "success");
+-                      if (res > 0) {
+-                              if (FD_ISSET(sock, &readfs))
+-                                      printf("ready for reading\n");
+-                              if (FD_ISSET(sock, &errorfs))
+-                                      printf("has error\n");
+-                              recvpacket(sock, 0,
+-                                         siocgstamp,
+-                                         siocgstampns);
+-                              recvpacket(sock, MSG_ERRQUEUE,
+-                                         siocgstamp,
+-                                         siocgstampns);
+-                      }
+-              } else {
+-                      /* write one packet */
+-                      sendpacket(sock,
+-                                 (struct sockaddr *)&addr,
+-                                 sizeof(addr));
+-                      next.tv_sec += 5;
+-                      continue;
+-              }
+-      }
+-
+-      return 0;
+-}
+--- a/Documentation/networking/timestamping/txtimestamp.c
++++ /dev/null
+@@ -1,549 +0,0 @@
+-/*
+- * Copyright 2014 Google Inc.
+- * Author: willemb@google.com (Willem de Bruijn)
+- *
+- * Test software tx timestamping, including
+- *
+- * - SCHED, SND and ACK timestamps
+- * - RAW, UDP and TCP
+- * - IPv4 and IPv6
+- * - various packet sizes (to test GSO and TSO)
+- *
+- * Consult the command line arguments for help on running
+- * the various testcases.
+- *
+- * This test requires a dummy TCP server.
+- * A simple `nc6 [-u] -l -p $DESTPORT` will do
+- *
+- *
+- * This program is free software; you can redistribute it and/or modify it
+- * under the terms and conditions of the GNU General Public License,
+- * version 2, as published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope it will be useful, but WITHOUT
+- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+- * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
+- * more details.
+- *
+- * You should have received a copy of the GNU General Public License along with
+- * this program; if not, write to the Free Software Foundation, Inc.,
+- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+- */
+-
+-#define _GNU_SOURCE
+-
+-#include <arpa/inet.h>
+-#include <asm/types.h>
+-#include <error.h>
+-#include <errno.h>
+-#include <inttypes.h>
+-#include <linux/errqueue.h>
+-#include <linux/if_ether.h>
+-#include <linux/net_tstamp.h>
+-#include <netdb.h>
+-#include <net/if.h>
+-#include <netinet/in.h>
+-#include <netinet/ip.h>
+-#include <netinet/udp.h>
+-#include <netinet/tcp.h>
+-#include <netpacket/packet.h>
+-#include <poll.h>
+-#include <stdarg.h>
+-#include <stdbool.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <sys/ioctl.h>
+-#include <sys/select.h>
+-#include <sys/socket.h>
+-#include <sys/time.h>
+-#include <sys/types.h>
+-#include <time.h>
+-#include <unistd.h>
+-
+-/* command line parameters */
+-static int cfg_proto = SOCK_STREAM;
+-static int cfg_ipproto = IPPROTO_TCP;
+-static int cfg_num_pkts = 4;
+-static int do_ipv4 = 1;
+-static int do_ipv6 = 1;
+-static int cfg_payload_len = 10;
+-static bool cfg_show_payload;
+-static bool cfg_do_pktinfo;
+-static bool cfg_loop_nodata;
+-static uint16_t dest_port = 9000;
+-
+-static struct sockaddr_in daddr;
+-static struct sockaddr_in6 daddr6;
+-static struct timespec ts_prev;
+-
+-static void __print_timestamp(const char *name, struct timespec *cur,
+-                            uint32_t key, int payload_len)
+-{
+-      if (!(cur->tv_sec | cur->tv_nsec))
+-              return;
+-
+-      fprintf(stderr, "  %s: %lu s %lu us (seq=%u, len=%u)",
+-                      name, cur->tv_sec, cur->tv_nsec / 1000,
+-                      key, payload_len);
+-
+-      if ((ts_prev.tv_sec | ts_prev.tv_nsec)) {
+-              int64_t cur_ms, prev_ms;
+-
+-              cur_ms = (long) cur->tv_sec * 1000 * 1000;
+-              cur_ms += cur->tv_nsec / 1000;
+-
+-              prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
+-              prev_ms += ts_prev.tv_nsec / 1000;
+-
+-              fprintf(stderr, "  (%+" PRId64 " us)", cur_ms - prev_ms);
+-      }
+-
+-      ts_prev = *cur;
+-      fprintf(stderr, "\n");
+-}
+-
+-static void print_timestamp_usr(void)
+-{
+-      struct timespec ts;
+-      struct timeval tv;      /* avoid dependency on -lrt */
+-
+-      gettimeofday(&tv, NULL);
+-      ts.tv_sec = tv.tv_sec;
+-      ts.tv_nsec = tv.tv_usec * 1000;
+-
+-      __print_timestamp("  USR", &ts, 0, 0);
+-}
+-
+-static void print_timestamp(struct scm_timestamping *tss, int tstype,
+-                          int tskey, int payload_len)
+-{
+-      const char *tsname;
+-
+-      switch (tstype) {
+-      case SCM_TSTAMP_SCHED:
+-              tsname = "  ENQ";
+-              break;
+-      case SCM_TSTAMP_SND:
+-              tsname = "  SND";
+-              break;
+-      case SCM_TSTAMP_ACK:
+-              tsname = "  ACK";
+-              break;
+-      default:
+-              error(1, 0, "unknown timestamp type: %u",
+-              tstype);
+-      }
+-      __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
+-}
+-
+-/* TODO: convert to check_and_print payload once API is stable */
+-static void print_payload(char *data, int len)
+-{
+-      int i;
+-
+-      if (!len)
+-              return;
+-
+-      if (len > 70)
+-              len = 70;
+-
+-      fprintf(stderr, "payload: ");
+-      for (i = 0; i < len; i++)
+-              fprintf(stderr, "%02hhx ", data[i]);
+-      fprintf(stderr, "\n");
+-}
+-
+-static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr)
+-{
+-      char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN];
+-
+-      fprintf(stderr, "         pktinfo: ifindex=%u src=%s dst=%s\n",
+-              ifindex,
+-              saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown",
+-              daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown");
+-}
+-
+-static void __poll(int fd)
+-{
+-      struct pollfd pollfd;
+-      int ret;
+-
+-      memset(&pollfd, 0, sizeof(pollfd));
+-      pollfd.fd = fd;
+-      ret = poll(&pollfd, 1, 100);
+-      if (ret != 1)
+-              error(1, errno, "poll");
+-}
+-
+-static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
+-{
+-      struct sock_extended_err *serr = NULL;
+-      struct scm_timestamping *tss = NULL;
+-      struct cmsghdr *cm;
+-      int batch = 0;
+-
+-      for (cm = CMSG_FIRSTHDR(msg);
+-           cm && cm->cmsg_len;
+-           cm = CMSG_NXTHDR(msg, cm)) {
+-              if (cm->cmsg_level == SOL_SOCKET &&
+-                  cm->cmsg_type == SCM_TIMESTAMPING) {
+-                      tss = (void *) CMSG_DATA(cm);
+-              } else if ((cm->cmsg_level == SOL_IP &&
+-                          cm->cmsg_type == IP_RECVERR) ||
+-                         (cm->cmsg_level == SOL_IPV6 &&
+-                          cm->cmsg_type == IPV6_RECVERR)) {
+-                      serr = (void *) CMSG_DATA(cm);
+-                      if (serr->ee_errno != ENOMSG ||
+-                          serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
+-                              fprintf(stderr, "unknown ip error %d %d\n",
+-                                              serr->ee_errno,
+-                                              serr->ee_origin);
+-                              serr = NULL;
+-                      }
+-              } else if (cm->cmsg_level == SOL_IP &&
+-                         cm->cmsg_type == IP_PKTINFO) {
+-                      struct in_pktinfo *info = (void *) CMSG_DATA(cm);
+-                      print_pktinfo(AF_INET, info->ipi_ifindex,
+-                                    &info->ipi_spec_dst, &info->ipi_addr);
+-              } else if (cm->cmsg_level == SOL_IPV6 &&
+-                         cm->cmsg_type == IPV6_PKTINFO) {
+-                      struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm);
+-                      print_pktinfo(AF_INET6, info6->ipi6_ifindex,
+-                                    NULL, &info6->ipi6_addr);
+-              } else
+-                      fprintf(stderr, "unknown cmsg %d,%d\n",
+-                                      cm->cmsg_level, cm->cmsg_type);
+-
+-              if (serr && tss) {
+-                      print_timestamp(tss, serr->ee_info, serr->ee_data,
+-                                      payload_len);
+-                      serr = NULL;
+-                      tss = NULL;
+-                      batch++;
+-              }
+-      }
+-
+-      if (batch > 1)
+-              fprintf(stderr, "batched %d timestamps\n", batch);
+-}
+-
+-static int recv_errmsg(int fd)
+-{
+-      static char ctrl[1024 /* overprovision*/];
+-      static struct msghdr msg;
+-      struct iovec entry;
+-      static char *data;
+-      int ret = 0;
+-
+-      data = malloc(cfg_payload_len);
+-      if (!data)
+-              error(1, 0, "malloc");
+-
+-      memset(&msg, 0, sizeof(msg));
+-      memset(&entry, 0, sizeof(entry));
+-      memset(ctrl, 0, sizeof(ctrl));
+-
+-      entry.iov_base = data;
+-      entry.iov_len = cfg_payload_len;
+-      msg.msg_iov = &entry;
+-      msg.msg_iovlen = 1;
+-      msg.msg_name = NULL;
+-      msg.msg_namelen = 0;
+-      msg.msg_control = ctrl;
+-      msg.msg_controllen = sizeof(ctrl);
+-
+-      ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
+-      if (ret == -1 && errno != EAGAIN)
+-              error(1, errno, "recvmsg");
+-
+-      if (ret >= 0) {
+-              __recv_errmsg_cmsg(&msg, ret);
+-              if (cfg_show_payload)
+-                      print_payload(data, cfg_payload_len);
+-      }
+-
+-      free(data);
+-      return ret == -1;
+-}
+-
+-static void do_test(int family, unsigned int opt)
+-{
+-      char *buf;
+-      int fd, i, val = 1, total_len;
+-
+-      if (family == AF_INET6 && cfg_proto != SOCK_STREAM) {
+-              /* due to lack of checksum generation code */
+-              fprintf(stderr, "test: skipping datagram over IPv6\n");
+-              return;
+-      }
+-
+-      total_len = cfg_payload_len;
+-      if (cfg_proto == SOCK_RAW) {
+-              total_len += sizeof(struct udphdr);
+-              if (cfg_ipproto == IPPROTO_RAW)
+-                      total_len += sizeof(struct iphdr);
+-      }
+-
+-      buf = malloc(total_len);
+-      if (!buf)
+-              error(1, 0, "malloc");
+-
+-      fd = socket(family, cfg_proto, cfg_ipproto);
+-      if (fd < 0)
+-              error(1, errno, "socket");
+-
+-      if (cfg_proto == SOCK_STREAM) {
+-              if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+-                             (char*) &val, sizeof(val)))
+-                      error(1, 0, "setsockopt no nagle");
+-
+-              if (family == PF_INET) {
+-                      if (connect(fd, (void *) &daddr, sizeof(daddr)))
+-                              error(1, errno, "connect ipv4");
+-              } else {
+-                      if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
+-                              error(1, errno, "connect ipv6");
+-              }
+-      }
+-
+-      if (cfg_do_pktinfo) {
+-              if (family == AF_INET6) {
+-                      if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO,
+-                                     &val, sizeof(val)))
+-                              error(1, errno, "setsockopt pktinfo ipv6");
+-              } else {
+-                      if (setsockopt(fd, SOL_IP, IP_PKTINFO,
+-                                     &val, sizeof(val)))
+-                              error(1, errno, "setsockopt pktinfo ipv4");
+-              }
+-      }
+-
+-      opt |= SOF_TIMESTAMPING_SOFTWARE |
+-             SOF_TIMESTAMPING_OPT_CMSG |
+-             SOF_TIMESTAMPING_OPT_ID;
+-      if (cfg_loop_nodata)
+-              opt |= SOF_TIMESTAMPING_OPT_TSONLY;
+-
+-      if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
+-                     (char *) &opt, sizeof(opt)))
+-              error(1, 0, "setsockopt timestamping");
+-
+-      for (i = 0; i < cfg_num_pkts; i++) {
+-              memset(&ts_prev, 0, sizeof(ts_prev));
+-              memset(buf, 'a' + i, total_len);
+-
+-              if (cfg_proto == SOCK_RAW) {
+-                      struct udphdr *udph;
+-                      int off = 0;
+-
+-                      if (cfg_ipproto == IPPROTO_RAW) {
+-                              struct iphdr *iph = (void *) buf;
+-
+-                              memset(iph, 0, sizeof(*iph));
+-                              iph->ihl      = 5;
+-                              iph->version  = 4;
+-                              iph->ttl      = 2;
+-                              iph->daddr    = daddr.sin_addr.s_addr;
+-                              iph->protocol = IPPROTO_UDP;
+-                              /* kernel writes saddr, csum, len */
+-
+-                              off = sizeof(*iph);
+-                      }
+-
+-                      udph = (void *) buf + off;
+-                      udph->source = ntohs(9000);     /* random spoof */
+-                      udph->dest   = ntohs(dest_port);
+-                      udph->len    = ntohs(sizeof(*udph) + cfg_payload_len);
+-                      udph->check  = 0;       /* not allowed for IPv6 */
+-              }
+-
+-              print_timestamp_usr();
+-              if (cfg_proto != SOCK_STREAM) {
+-                      if (family == PF_INET)
+-                              val = sendto(fd, buf, total_len, 0, (void *) &daddr, sizeof(daddr));
+-                      else
+-                              val = sendto(fd, buf, total_len, 0, (void *) &daddr6, sizeof(daddr6));
+-              } else {
+-                      val = send(fd, buf, cfg_payload_len, 0);
+-              }
+-              if (val != total_len)
+-                      error(1, errno, "send");
+-
+-              /* wait for all errors to be queued, else ACKs arrive OOO */
+-              usleep(50 * 1000);
+-
+-              __poll(fd);
+-
+-              while (!recv_errmsg(fd)) {}
+-      }
+-
+-      if (close(fd))
+-              error(1, errno, "close");
+-
+-      free(buf);
+-      usleep(400 * 1000);
+-}
+-
+-static void __attribute__((noreturn)) usage(const char *filepath)
+-{
+-      fprintf(stderr, "\nUsage: %s [options] hostname\n"
+-                      "\nwhere options are:\n"
+-                      "  -4:   only IPv4\n"
+-                      "  -6:   only IPv6\n"
+-                      "  -h:   show this message\n"
+-                      "  -I:   request PKTINFO\n"
+-                      "  -l N: send N bytes at a time\n"
+-                      "  -n:   set no-payload option\n"
+-                      "  -r:   use raw\n"
+-                      "  -R:   use raw (IP_HDRINCL)\n"
+-                      "  -p N: connect to port N\n"
+-                      "  -u:   use udp\n"
+-                      "  -x:   show payload (up to 70 bytes)\n",
+-                      filepath);
+-      exit(1);
+-}
+-
+-static void parse_opt(int argc, char **argv)
+-{
+-      int proto_count = 0;
+-      char c;
+-
+-      while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) {
+-              switch (c) {
+-              case '4':
+-                      do_ipv6 = 0;
+-                      break;
+-              case '6':
+-                      do_ipv4 = 0;
+-                      break;
+-              case 'I':
+-                      cfg_do_pktinfo = true;
+-                      break;
+-              case 'n':
+-                      cfg_loop_nodata = true;
+-                      break;
+-              case 'r':
+-                      proto_count++;
+-                      cfg_proto = SOCK_RAW;
+-                      cfg_ipproto = IPPROTO_UDP;
+-                      break;
+-              case 'R':
+-                      proto_count++;
+-                      cfg_proto = SOCK_RAW;
+-                      cfg_ipproto = IPPROTO_RAW;
+-                      break;
+-              case 'u':
+-                      proto_count++;
+-                      cfg_proto = SOCK_DGRAM;
+-                      cfg_ipproto = IPPROTO_UDP;
+-                      break;
+-              case 'l':
+-                      cfg_payload_len = strtoul(optarg, NULL, 10);
+-                      break;
+-              case 'p':
+-                      dest_port = strtoul(optarg, NULL, 10);
+-                      break;
+-              case 'x':
+-                      cfg_show_payload = true;
+-                      break;
+-              case 'h':
+-              default:
+-                      usage(argv[0]);
+-              }
+-      }
+-
+-      if (!cfg_payload_len)
+-              error(1, 0, "payload may not be nonzero");
+-      if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
+-              error(1, 0, "udp packet might exceed expected MTU");
+-      if (!do_ipv4 && !do_ipv6)
+-              error(1, 0, "pass -4 or -6, not both");
+-      if (proto_count > 1)
+-              error(1, 0, "pass -r, -R or -u, not multiple");
+-
+-      if (optind != argc - 1)
+-              error(1, 0, "missing required hostname argument");
+-}
+-
+-static void resolve_hostname(const char *hostname)
+-{
+-      struct addrinfo *addrs, *cur;
+-      int have_ipv4 = 0, have_ipv6 = 0;
+-
+-      if (getaddrinfo(hostname, NULL, NULL, &addrs))
+-              error(1, errno, "getaddrinfo");
+-
+-      cur = addrs;
+-      while (cur && !have_ipv4 && !have_ipv6) {
+-              if (!have_ipv4 && cur->ai_family == AF_INET) {
+-                      memcpy(&daddr, cur->ai_addr, sizeof(daddr));
+-                      daddr.sin_port = htons(dest_port);
+-                      have_ipv4 = 1;
+-              }
+-              else if (!have_ipv6 && cur->ai_family == AF_INET6) {
+-                      memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
+-                      daddr6.sin6_port = htons(dest_port);
+-                      have_ipv6 = 1;
+-              }
+-              cur = cur->ai_next;
+-      }
+-      if (addrs)
+-              freeaddrinfo(addrs);
+-
+-      do_ipv4 &= have_ipv4;
+-      do_ipv6 &= have_ipv6;
+-}
+-
+-static void do_main(int family)
+-{
+-      fprintf(stderr, "family:       %s\n",
+-                      family == PF_INET ? "INET" : "INET6");
+-
+-      fprintf(stderr, "test SND\n");
+-      do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
+-
+-      fprintf(stderr, "test ENQ\n");
+-      do_test(family, SOF_TIMESTAMPING_TX_SCHED);
+-
+-      fprintf(stderr, "test ENQ + SND\n");
+-      do_test(family, SOF_TIMESTAMPING_TX_SCHED |
+-                      SOF_TIMESTAMPING_TX_SOFTWARE);
+-
+-      if (cfg_proto == SOCK_STREAM) {
+-              fprintf(stderr, "\ntest ACK\n");
+-              do_test(family, SOF_TIMESTAMPING_TX_ACK);
+-
+-              fprintf(stderr, "\ntest SND + ACK\n");
+-              do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
+-                              SOF_TIMESTAMPING_TX_ACK);
+-
+-              fprintf(stderr, "\ntest ENQ + SND + ACK\n");
+-              do_test(family, SOF_TIMESTAMPING_TX_SCHED |
+-                              SOF_TIMESTAMPING_TX_SOFTWARE |
+-                              SOF_TIMESTAMPING_TX_ACK);
+-      }
+-}
+-
+-const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
+-
+-int main(int argc, char **argv)
+-{
+-      if (argc == 1)
+-              usage(argv[0]);
+-
+-      parse_opt(argc, argv);
+-      resolve_hostname(argv[argc - 1]);
+-
+-      fprintf(stderr, "protocol:     %s\n", sock_names[cfg_proto]);
+-      fprintf(stderr, "payload:      %u\n", cfg_payload_len);
+-      fprintf(stderr, "server port:  %u\n", dest_port);
+-      fprintf(stderr, "\n");
+-
+-      if (do_ipv4)
+-              do_main(PF_INET);
+-      if (do_ipv6)
+-              do_main(PF_INET6);
+-
+-      return 0;
+-}
+--- /dev/null
++++ b/tools/testing/selftests/networking/timestamping/.gitignore
+@@ -0,0 +1,3 @@
++timestamping
++txtimestamp
++hwtstamp_config
+--- /dev/null
++++ b/tools/testing/selftests/networking/timestamping/Makefile
+@@ -0,0 +1,8 @@
++TEST_PROGS := hwtstamp_config timestamping txtimestamp
++
++all: $(TEST_PROGS)
++
++include ../../lib.mk
++
++clean:
++      rm -fr $(TEST_PROGS)
+--- /dev/null
++++ b/tools/testing/selftests/networking/timestamping/hwtstamp_config.c
+@@ -0,0 +1,134 @@
++/* Test program for SIOC{G,S}HWTSTAMP
++ * Copyright 2013 Solarflare Communications
++ * Author: Ben Hutchings
++ */
++
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <sys/socket.h>
++#include <sys/ioctl.h>
++
++#include <linux/if.h>
++#include <linux/net_tstamp.h>
++#include <linux/sockios.h>
++
++static int
++lookup_value(const char **names, int size, const char *name)
++{
++      int value;
++
++      for (value = 0; value < size; value++)
++              if (names[value] && strcasecmp(names[value], name) == 0)
++                      return value;
++
++      return -1;
++}
++
++static const char *
++lookup_name(const char **names, int size, int value)
++{
++      return (value >= 0 && value < size) ? names[value] : NULL;
++}
++
++static void list_names(FILE *f, const char **names, int size)
++{
++      int value;
++
++      for (value = 0; value < size; value++)
++              if (names[value])
++                      fprintf(f, "    %s\n", names[value]);
++}
++
++static const char *tx_types[] = {
++#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name
++      TX_TYPE(OFF),
++      TX_TYPE(ON),
++      TX_TYPE(ONESTEP_SYNC)
++#undef TX_TYPE
++};
++#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0])))
++
++static const char *rx_filters[] = {
++#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name
++      RX_FILTER(NONE),
++      RX_FILTER(ALL),
++      RX_FILTER(SOME),
++      RX_FILTER(PTP_V1_L4_EVENT),
++      RX_FILTER(PTP_V1_L4_SYNC),
++      RX_FILTER(PTP_V1_L4_DELAY_REQ),
++      RX_FILTER(PTP_V2_L4_EVENT),
++      RX_FILTER(PTP_V2_L4_SYNC),
++      RX_FILTER(PTP_V2_L4_DELAY_REQ),
++      RX_FILTER(PTP_V2_L2_EVENT),
++      RX_FILTER(PTP_V2_L2_SYNC),
++      RX_FILTER(PTP_V2_L2_DELAY_REQ),
++      RX_FILTER(PTP_V2_EVENT),
++      RX_FILTER(PTP_V2_SYNC),
++      RX_FILTER(PTP_V2_DELAY_REQ),
++#undef RX_FILTER
++};
++#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0])))
++
++static void usage(void)
++{
++      fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n"
++            "tx_type is any of (case-insensitive):\n",
++            stderr);
++      list_names(stderr, tx_types, N_TX_TYPES);
++      fputs("rx_filter is any of (case-insensitive):\n", stderr);
++      list_names(stderr, rx_filters, N_RX_FILTERS);
++}
++
++int main(int argc, char **argv)
++{
++      struct ifreq ifr;
++      struct hwtstamp_config config;
++      const char *name;
++      int sock;
++
++      if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) {
++              usage();
++              return 2;
++      }
++
++      if (argc == 4) {
++              config.flags = 0;
++              config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]);
++              config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]);
++              if (config.tx_type < 0 || config.rx_filter < 0) {
++                      usage();
++                      return 2;
++              }
++      }
++
++      sock = socket(AF_INET, SOCK_DGRAM, 0);
++      if (sock < 0) {
++              perror("socket");
++              return 1;
++      }
++
++      strcpy(ifr.ifr_name, argv[1]);
++      ifr.ifr_data = (caddr_t)&config;
++
++      if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) {
++              perror("ioctl");
++              return 1;
++      }
++
++      printf("flags = %#x\n", config.flags);
++      name = lookup_name(tx_types, N_TX_TYPES, config.tx_type);
++      if (name)
++              printf("tx_type = %s\n", name);
++      else
++              printf("tx_type = %d\n", config.tx_type);
++      name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter);
++      if (name)
++              printf("rx_filter = %s\n", name);
++      else
++              printf("rx_filter = %d\n", config.rx_filter);
++
++      return 0;
++}
+--- /dev/null
++++ b/tools/testing/selftests/networking/timestamping/timestamping.c
+@@ -0,0 +1,528 @@
++/*
++ * This program demonstrates how the various time stamping features in
++ * the Linux kernel work. It emulates the behavior of a PTP
++ * implementation in stand-alone master mode by sending PTPv1 Sync
++ * multicasts once every second. It looks for similar packets, but
++ * beyond that doesn't actually implement PTP.
++ *
++ * Outgoing packets are time stamped with SO_TIMESTAMPING with or
++ * without hardware support.
++ *
++ * Incoming packets are time stamped with SO_TIMESTAMPING with or
++ * without hardware support, SIOCGSTAMP[NS] (per-socket time stamp) and
++ * SO_TIMESTAMP[NS].
++ *
++ * Copyright (C) 2009 Intel Corporation.
++ * Author: Patrick Ohly <patrick.ohly@intel.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++
++#include <sys/time.h>
++#include <sys/socket.h>
++#include <sys/select.h>
++#include <sys/ioctl.h>
++#include <arpa/inet.h>
++#include <net/if.h>
++
++#include <asm/types.h>
++#include <linux/net_tstamp.h>
++#include <linux/errqueue.h>
++
++#ifndef SO_TIMESTAMPING
++# define SO_TIMESTAMPING         37
++# define SCM_TIMESTAMPING        SO_TIMESTAMPING
++#endif
++
++#ifndef SO_TIMESTAMPNS
++# define SO_TIMESTAMPNS 35
++#endif
++
++#ifndef SIOCGSTAMPNS
++# define SIOCGSTAMPNS 0x8907
++#endif
++
++#ifndef SIOCSHWTSTAMP
++# define SIOCSHWTSTAMP 0x89b0
++#endif
++
++static void usage(const char *error)
++{
++      if (error)
++              printf("invalid option: %s\n", error);
++      printf("timestamping interface option*\n\n"
++             "Options:\n"
++             "  IP_MULTICAST_LOOP - looping outgoing multicasts\n"
++             "  SO_TIMESTAMP - normal software time stamping, ms resolution\n"
++             "  SO_TIMESTAMPNS - more accurate software time stamping\n"
++             "  SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n"
++             "  SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n"
++             "  SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n"
++             "  SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n"
++             "  SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n"
++             "  SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
++             "  SIOCGSTAMP - check last socket time stamp\n"
++             "  SIOCGSTAMPNS - more accurate socket time stamp\n");
++      exit(1);
++}
++
++static void bail(const char *error)
++{
++      printf("%s: %s\n", error, strerror(errno));
++      exit(1);
++}
++
++static const unsigned char sync[] = {
++      0x00, 0x01, 0x00, 0x01,
++      0x5f, 0x44, 0x46, 0x4c,
++      0x54, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x01, 0x01,
++
++      /* fake uuid */
++      0x00, 0x01,
++      0x02, 0x03, 0x04, 0x05,
++
++      0x00, 0x01, 0x00, 0x37,
++      0x00, 0x00, 0x00, 0x08,
++      0x00, 0x00, 0x00, 0x00,
++      0x49, 0x05, 0xcd, 0x01,
++      0x29, 0xb1, 0x8d, 0xb0,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x01,
++
++      /* fake uuid */
++      0x00, 0x01,
++      0x02, 0x03, 0x04, 0x05,
++
++      0x00, 0x00, 0x00, 0x37,
++      0x00, 0x00, 0x00, 0x04,
++      0x44, 0x46, 0x4c, 0x54,
++      0x00, 0x00, 0xf0, 0x60,
++      0x00, 0x01, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x01,
++      0x00, 0x00, 0xf0, 0x60,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x04,
++      0x44, 0x46, 0x4c, 0x54,
++      0x00, 0x01,
++
++      /* fake uuid */
++      0x00, 0x01,
++      0x02, 0x03, 0x04, 0x05,
++
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00
++};
++
++static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len)
++{
++      struct timeval now;
++      int res;
++
++      res = sendto(sock, sync, sizeof(sync), 0,
++              addr, addr_len);
++      gettimeofday(&now, 0);
++      if (res < 0)
++              printf("%s: %s\n", "send", strerror(errno));
++      else
++              printf("%ld.%06ld: sent %d bytes\n",
++                     (long)now.tv_sec, (long)now.tv_usec,
++                     res);
++}
++
++static void printpacket(struct msghdr *msg, int res,
++                      char *data,
++                      int sock, int recvmsg_flags,
++                      int siocgstamp, int siocgstampns)
++{
++      struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
++      struct cmsghdr *cmsg;
++      struct timeval tv;
++      struct timespec ts;
++      struct timeval now;
++
++      gettimeofday(&now, 0);
++
++      printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
++             (long)now.tv_sec, (long)now.tv_usec,
++             (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
++             res,
++             inet_ntoa(from_addr->sin_addr),
++             msg->msg_controllen);
++      for (cmsg = CMSG_FIRSTHDR(msg);
++           cmsg;
++           cmsg = CMSG_NXTHDR(msg, cmsg)) {
++              printf("   cmsg len %zu: ", cmsg->cmsg_len);
++              switch (cmsg->cmsg_level) {
++              case SOL_SOCKET:
++                      printf("SOL_SOCKET ");
++                      switch (cmsg->cmsg_type) {
++                      case SO_TIMESTAMP: {
++                              struct timeval *stamp =
++                                      (struct timeval *)CMSG_DATA(cmsg);
++                              printf("SO_TIMESTAMP %ld.%06ld",
++                                     (long)stamp->tv_sec,
++                                     (long)stamp->tv_usec);
++                              break;
++                      }
++                      case SO_TIMESTAMPNS: {
++                              struct timespec *stamp =
++                                      (struct timespec *)CMSG_DATA(cmsg);
++                              printf("SO_TIMESTAMPNS %ld.%09ld",
++                                     (long)stamp->tv_sec,
++                                     (long)stamp->tv_nsec);
++                              break;
++                      }
++                      case SO_TIMESTAMPING: {
++                              struct timespec *stamp =
++                                      (struct timespec *)CMSG_DATA(cmsg);
++                              printf("SO_TIMESTAMPING ");
++                              printf("SW %ld.%09ld ",
++                                     (long)stamp->tv_sec,
++                                     (long)stamp->tv_nsec);
++                              stamp++;
++                              /* skip deprecated HW transformed */
++                              stamp++;
++                              printf("HW raw %ld.%09ld",
++                                     (long)stamp->tv_sec,
++                                     (long)stamp->tv_nsec);
++                              break;
++                      }
++                      default:
++                              printf("type %d", cmsg->cmsg_type);
++                              break;
++                      }
++                      break;
++              case IPPROTO_IP:
++                      printf("IPPROTO_IP ");
++                      switch (cmsg->cmsg_type) {
++                      case IP_RECVERR: {
++                              struct sock_extended_err *err =
++                                      (struct sock_extended_err *)CMSG_DATA(cmsg);
++                              printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s",
++                                      strerror(err->ee_errno),
++                                      err->ee_origin,
++#ifdef SO_EE_ORIGIN_TIMESTAMPING
++                                      err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ?
++                                      "bounced packet" : "unexpected origin"
++#else
++                                      "probably SO_EE_ORIGIN_TIMESTAMPING"
++#endif
++                                      );
++                              if (res < sizeof(sync))
++                                      printf(" => truncated data?!");
++                              else if (!memcmp(sync, data + res - sizeof(sync),
++                                                      sizeof(sync)))
++                                      printf(" => GOT OUR DATA BACK (HURRAY!)");
++                              break;
++                      }
++                      case IP_PKTINFO: {
++                              struct in_pktinfo *pktinfo =
++                                      (struct in_pktinfo *)CMSG_DATA(cmsg);
++                              printf("IP_PKTINFO interface index %u",
++                                      pktinfo->ipi_ifindex);
++                              break;
++                      }
++                      default:
++                              printf("type %d", cmsg->cmsg_type);
++                              break;
++                      }
++                      break;
++              default:
++                      printf("level %d type %d",
++                              cmsg->cmsg_level,
++                              cmsg->cmsg_type);
++                      break;
++              }
++              printf("\n");
++      }
++
++      if (siocgstamp) {
++              if (ioctl(sock, SIOCGSTAMP, &tv))
++                      printf("   %s: %s\n", "SIOCGSTAMP", strerror(errno));
++              else
++                      printf("SIOCGSTAMP %ld.%06ld\n",
++                             (long)tv.tv_sec,
++                             (long)tv.tv_usec);
++      }
++      if (siocgstampns) {
++              if (ioctl(sock, SIOCGSTAMPNS, &ts))
++                      printf("   %s: %s\n", "SIOCGSTAMPNS", strerror(errno));
++              else
++                      printf("SIOCGSTAMPNS %ld.%09ld\n",
++                             (long)ts.tv_sec,
++                             (long)ts.tv_nsec);
++      }
++}
++
++static void recvpacket(int sock, int recvmsg_flags,
++                     int siocgstamp, int siocgstampns)
++{
++      char data[256];
++      struct msghdr msg;
++      struct iovec entry;
++      struct sockaddr_in from_addr;
++      struct {
++              struct cmsghdr cm;
++              char control[512];
++      } control;
++      int res;
++
++      memset(&msg, 0, sizeof(msg));
++      msg.msg_iov = &entry;
++      msg.msg_iovlen = 1;
++      entry.iov_base = data;
++      entry.iov_len = sizeof(data);
++      msg.msg_name = (caddr_t)&from_addr;
++      msg.msg_namelen = sizeof(from_addr);
++      msg.msg_control = &control;
++      msg.msg_controllen = sizeof(control);
++
++      res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
++      if (res < 0) {
++              printf("%s %s: %s\n",
++                     "recvmsg",
++                     (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
++                     strerror(errno));
++      } else {
++              printpacket(&msg, res, data,
++                          sock, recvmsg_flags,
++                          siocgstamp, siocgstampns);
++      }
++}
++
++int main(int argc, char **argv)
++{
++      int so_timestamping_flags = 0;
++      int so_timestamp = 0;
++      int so_timestampns = 0;
++      int siocgstamp = 0;
++      int siocgstampns = 0;
++      int ip_multicast_loop = 0;
++      char *interface;
++      int i;
++      int enabled = 1;
++      int sock;
++      struct ifreq device;
++      struct ifreq hwtstamp;
++      struct hwtstamp_config hwconfig, hwconfig_requested;
++      struct sockaddr_in addr;
++      struct ip_mreq imr;
++      struct in_addr iaddr;
++      int val;
++      socklen_t len;
++      struct timeval next;
++
++      if (argc < 2)
++              usage(0);
++      interface = argv[1];
++
++      for (i = 2; i < argc; i++) {
++              if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
++                      so_timestamp = 1;
++              else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
++                      so_timestampns = 1;
++              else if (!strcasecmp(argv[i], "SIOCGSTAMP"))
++                      siocgstamp = 1;
++              else if (!strcasecmp(argv[i], "SIOCGSTAMPNS"))
++                      siocgstampns = 1;
++              else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP"))
++                      ip_multicast_loop = 1;
++              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE"))
++                      so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
++              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE"))
++                      so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
++              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE"))
++                      so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE;
++              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE"))
++                      so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
++              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE"))
++                      so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE;
++              else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE"))
++                      so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
++              else
++                      usage(argv[i]);
++      }
++
++      sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
++      if (sock < 0)
++              bail("socket");
++
++      memset(&device, 0, sizeof(device));
++      strncpy(device.ifr_name, interface, sizeof(device.ifr_name));
++      if (ioctl(sock, SIOCGIFADDR, &device) < 0)
++              bail("getting interface IP address");
++
++      memset(&hwtstamp, 0, sizeof(hwtstamp));
++      strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name));
++      hwtstamp.ifr_data = (void *)&hwconfig;
++      memset(&hwconfig, 0, sizeof(hwconfig));
++      hwconfig.tx_type =
++              (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ?
++              HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
++      hwconfig.rx_filter =
++              (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ?
++              HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE;
++      hwconfig_requested = hwconfig;
++      if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) {
++              if ((errno == EINVAL || errno == ENOTSUP) &&
++                  hwconfig_requested.tx_type == HWTSTAMP_TX_OFF &&
++                  hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE)
++                      printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
++              else
++                      bail("SIOCSHWTSTAMP");
++      }
++      printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
++             hwconfig_requested.tx_type, hwconfig.tx_type,
++             hwconfig_requested.rx_filter, hwconfig.rx_filter);
++
++      /* bind to PTP port */
++      addr.sin_family = AF_INET;
++      addr.sin_addr.s_addr = htonl(INADDR_ANY);
++      addr.sin_port = htons(319 /* PTP event port */);
++      if (bind(sock,
++               (struct sockaddr *)&addr,
++               sizeof(struct sockaddr_in)) < 0)
++              bail("bind");
++
++      /* set multicast group for outgoing packets */
++      inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
++      addr.sin_addr = iaddr;
++      imr.imr_multiaddr.s_addr = iaddr.s_addr;
++      imr.imr_interface.s_addr =
++              ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
++      if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
++                     &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
++              bail("set multicast");
++
++      /* join multicast group, loop our own packet */
++      if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
++                     &imr, sizeof(struct ip_mreq)) < 0)
++              bail("join multicast group");
++
++      if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
++                     &ip_multicast_loop, sizeof(enabled)) < 0) {
++              bail("loop multicast");
++      }
++
++      /* set socket options for time stamping */
++      if (so_timestamp &&
++              setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
++                         &enabled, sizeof(enabled)) < 0)
++              bail("setsockopt SO_TIMESTAMP");
++
++      if (so_timestampns &&
++              setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
++                         &enabled, sizeof(enabled)) < 0)
++              bail("setsockopt SO_TIMESTAMPNS");
++
++      if (so_timestamping_flags &&
++              setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,
++                         &so_timestamping_flags,
++                         sizeof(so_timestamping_flags)) < 0)
++              bail("setsockopt SO_TIMESTAMPING");
++
++      /* request IP_PKTINFO for debugging purposes */
++      if (setsockopt(sock, SOL_IP, IP_PKTINFO,
++                     &enabled, sizeof(enabled)) < 0)
++              printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno));
++
++      /* verify socket options */
++      len = sizeof(val);
++      if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
++              printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
++      else
++              printf("SO_TIMESTAMP %d\n", val);
++
++      if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
++              printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS",
++                     strerror(errno));
++      else
++              printf("SO_TIMESTAMPNS %d\n", val);
++
++      if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) {
++              printf("%s: %s\n", "getsockopt SO_TIMESTAMPING",
++                     strerror(errno));
++      } else {
++              printf("SO_TIMESTAMPING %d\n", val);
++              if (val != so_timestamping_flags)
++                      printf("   not the expected value %d\n",
++                             so_timestamping_flags);
++      }
++
++      /* send packets forever every five seconds */
++      gettimeofday(&next, 0);
++      next.tv_sec = (next.tv_sec + 1) / 5 * 5;
++      next.tv_usec = 0;
++      while (1) {
++              struct timeval now;
++              struct timeval delta;
++              long delta_us;
++              int res;
++              fd_set readfs, errorfs;
++
++              gettimeofday(&now, 0);
++              delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
++                      (long)(next.tv_usec - now.tv_usec);
++              if (delta_us > 0) {
++                      /* continue waiting for timeout or data */
++                      delta.tv_sec = delta_us / 1000000;
++                      delta.tv_usec = delta_us % 1000000;
++
++                      FD_ZERO(&readfs);
++                      FD_ZERO(&errorfs);
++                      FD_SET(sock, &readfs);
++                      FD_SET(sock, &errorfs);
++                      printf("%ld.%06ld: select %ldus\n",
++                             (long)now.tv_sec, (long)now.tv_usec,
++                             delta_us);
++                      res = select(sock + 1, &readfs, 0, &errorfs, &delta);
++                      gettimeofday(&now, 0);
++                      printf("%ld.%06ld: select returned: %d, %s\n",
++                             (long)now.tv_sec, (long)now.tv_usec,
++                             res,
++                             res < 0 ? strerror(errno) : "success");
++                      if (res > 0) {
++                              if (FD_ISSET(sock, &readfs))
++                                      printf("ready for reading\n");
++                              if (FD_ISSET(sock, &errorfs))
++                                      printf("has error\n");
++                              recvpacket(sock, 0,
++                                         siocgstamp,
++                                         siocgstampns);
++                              recvpacket(sock, MSG_ERRQUEUE,
++                                         siocgstamp,
++                                         siocgstampns);
++                      }
++              } else {
++                      /* write one packet */
++                      sendpacket(sock,
++                                 (struct sockaddr *)&addr,
++                                 sizeof(addr));
++                      next.tv_sec += 5;
++                      continue;
++              }
++      }
++
++      return 0;
++}
+--- /dev/null
++++ b/tools/testing/selftests/networking/timestamping/txtimestamp.c
+@@ -0,0 +1,549 @@
++/*
++ * Copyright 2014 Google Inc.
++ * Author: willemb@google.com (Willem de Bruijn)
++ *
++ * Test software tx timestamping, including
++ *
++ * - SCHED, SND and ACK timestamps
++ * - RAW, UDP and TCP
++ * - IPv4 and IPv6
++ * - various packet sizes (to test GSO and TSO)
++ *
++ * Consult the command line arguments for help on running
++ * the various testcases.
++ *
++ * This test requires a dummy TCP server.
++ * A simple `nc6 [-u] -l -p $DESTPORT` will do
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#define _GNU_SOURCE
++
++#include <arpa/inet.h>
++#include <asm/types.h>
++#include <error.h>
++#include <errno.h>
++#include <inttypes.h>
++#include <linux/errqueue.h>
++#include <linux/if_ether.h>
++#include <linux/net_tstamp.h>
++#include <netdb.h>
++#include <net/if.h>
++#include <netinet/in.h>
++#include <netinet/ip.h>
++#include <netinet/udp.h>
++#include <netinet/tcp.h>
++#include <netpacket/packet.h>
++#include <poll.h>
++#include <stdarg.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/ioctl.h>
++#include <sys/select.h>
++#include <sys/socket.h>
++#include <sys/time.h>
++#include <sys/types.h>
++#include <time.h>
++#include <unistd.h>
++
++/* command line parameters */
++static int cfg_proto = SOCK_STREAM;
++static int cfg_ipproto = IPPROTO_TCP;
++static int cfg_num_pkts = 4;
++static int do_ipv4 = 1;
++static int do_ipv6 = 1;
++static int cfg_payload_len = 10;
++static bool cfg_show_payload;
++static bool cfg_do_pktinfo;
++static bool cfg_loop_nodata;
++static uint16_t dest_port = 9000;
++
++static struct sockaddr_in daddr;
++static struct sockaddr_in6 daddr6;
++static struct timespec ts_prev;
++
++static void __print_timestamp(const char *name, struct timespec *cur,
++                            uint32_t key, int payload_len)
++{
++      if (!(cur->tv_sec | cur->tv_nsec))
++              return;
++
++      fprintf(stderr, "  %s: %lu s %lu us (seq=%u, len=%u)",
++                      name, cur->tv_sec, cur->tv_nsec / 1000,
++                      key, payload_len);
++
++      if ((ts_prev.tv_sec | ts_prev.tv_nsec)) {
++              int64_t cur_ms, prev_ms;
++
++              cur_ms = (long) cur->tv_sec * 1000 * 1000;
++              cur_ms += cur->tv_nsec / 1000;
++
++              prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
++              prev_ms += ts_prev.tv_nsec / 1000;
++
++              fprintf(stderr, "  (%+" PRId64 " us)", cur_ms - prev_ms);
++      }
++
++      ts_prev = *cur;
++      fprintf(stderr, "\n");
++}
++
++static void print_timestamp_usr(void)
++{
++      struct timespec ts;
++      struct timeval tv;      /* avoid dependency on -lrt */
++
++      gettimeofday(&tv, NULL);
++      ts.tv_sec = tv.tv_sec;
++      ts.tv_nsec = tv.tv_usec * 1000;
++
++      __print_timestamp("  USR", &ts, 0, 0);
++}
++
++static void print_timestamp(struct scm_timestamping *tss, int tstype,
++                          int tskey, int payload_len)
++{
++      const char *tsname;
++
++      switch (tstype) {
++      case SCM_TSTAMP_SCHED:
++              tsname = "  ENQ";
++              break;
++      case SCM_TSTAMP_SND:
++              tsname = "  SND";
++              break;
++      case SCM_TSTAMP_ACK:
++              tsname = "  ACK";
++              break;
++      default:
++              error(1, 0, "unknown timestamp type: %u",
++              tstype);
++      }
++      __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
++}
++
++/* TODO: convert to check_and_print payload once API is stable */
++static void print_payload(char *data, int len)
++{
++      int i;
++
++      if (!len)
++              return;
++
++      if (len > 70)
++              len = 70;
++
++      fprintf(stderr, "payload: ");
++      for (i = 0; i < len; i++)
++              fprintf(stderr, "%02hhx ", data[i]);
++      fprintf(stderr, "\n");
++}
++
++static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr)
++{
++      char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN];
++
++      fprintf(stderr, "         pktinfo: ifindex=%u src=%s dst=%s\n",
++              ifindex,
++              saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown",
++              daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown");
++}
++
++static void __poll(int fd)
++{
++      struct pollfd pollfd;
++      int ret;
++
++      memset(&pollfd, 0, sizeof(pollfd));
++      pollfd.fd = fd;
++      ret = poll(&pollfd, 1, 100);
++      if (ret != 1)
++              error(1, errno, "poll");
++}
++
++static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
++{
++      struct sock_extended_err *serr = NULL;
++      struct scm_timestamping *tss = NULL;
++      struct cmsghdr *cm;
++      int batch = 0;
++
++      for (cm = CMSG_FIRSTHDR(msg);
++           cm && cm->cmsg_len;
++           cm = CMSG_NXTHDR(msg, cm)) {
++              if (cm->cmsg_level == SOL_SOCKET &&
++                  cm->cmsg_type == SCM_TIMESTAMPING) {
++                      tss = (void *) CMSG_DATA(cm);
++              } else if ((cm->cmsg_level == SOL_IP &&
++                          cm->cmsg_type == IP_RECVERR) ||
++                         (cm->cmsg_level == SOL_IPV6 &&
++                          cm->cmsg_type == IPV6_RECVERR)) {
++                      serr = (void *) CMSG_DATA(cm);
++                      if (serr->ee_errno != ENOMSG ||
++                          serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
++                              fprintf(stderr, "unknown ip error %d %d\n",
++                                              serr->ee_errno,
++                                              serr->ee_origin);
++                              serr = NULL;
++                      }
++              } else if (cm->cmsg_level == SOL_IP &&
++                         cm->cmsg_type == IP_PKTINFO) {
++                      struct in_pktinfo *info = (void *) CMSG_DATA(cm);
++                      print_pktinfo(AF_INET, info->ipi_ifindex,
++                                    &info->ipi_spec_dst, &info->ipi_addr);
++              } else if (cm->cmsg_level == SOL_IPV6 &&
++                         cm->cmsg_type == IPV6_PKTINFO) {
++                      struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm);
++                      print_pktinfo(AF_INET6, info6->ipi6_ifindex,
++                                    NULL, &info6->ipi6_addr);
++              } else
++                      fprintf(stderr, "unknown cmsg %d,%d\n",
++                                      cm->cmsg_level, cm->cmsg_type);
++
++              if (serr && tss) {
++                      print_timestamp(tss, serr->ee_info, serr->ee_data,
++                                      payload_len);
++                      serr = NULL;
++                      tss = NULL;
++                      batch++;
++              }
++      }
++
++      if (batch > 1)
++              fprintf(stderr, "batched %d timestamps\n", batch);
++}
++
++static int recv_errmsg(int fd)
++{
++      static char ctrl[1024 /* overprovision*/];
++      static struct msghdr msg;
++      struct iovec entry;
++      static char *data;
++      int ret = 0;
++
++      data = malloc(cfg_payload_len);
++      if (!data)
++              error(1, 0, "malloc");
++
++      memset(&msg, 0, sizeof(msg));
++      memset(&entry, 0, sizeof(entry));
++      memset(ctrl, 0, sizeof(ctrl));
++
++      entry.iov_base = data;
++      entry.iov_len = cfg_payload_len;
++      msg.msg_iov = &entry;
++      msg.msg_iovlen = 1;
++      msg.msg_name = NULL;
++      msg.msg_namelen = 0;
++      msg.msg_control = ctrl;
++      msg.msg_controllen = sizeof(ctrl);
++
++      ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
++      if (ret == -1 && errno != EAGAIN)
++              error(1, errno, "recvmsg");
++
++      if (ret >= 0) {
++              __recv_errmsg_cmsg(&msg, ret);
++              if (cfg_show_payload)
++                      print_payload(data, cfg_payload_len);
++      }
++
++      free(data);
++      return ret == -1;
++}
++
++static void do_test(int family, unsigned int opt)
++{
++      char *buf;
++      int fd, i, val = 1, total_len;
++
++      if (family == AF_INET6 && cfg_proto != SOCK_STREAM) {
++              /* due to lack of checksum generation code */
++              fprintf(stderr, "test: skipping datagram over IPv6\n");
++              return;
++      }
++
++      total_len = cfg_payload_len;
++      if (cfg_proto == SOCK_RAW) {
++              total_len += sizeof(struct udphdr);
++              if (cfg_ipproto == IPPROTO_RAW)
++                      total_len += sizeof(struct iphdr);
++      }
++
++      buf = malloc(total_len);
++      if (!buf)
++              error(1, 0, "malloc");
++
++      fd = socket(family, cfg_proto, cfg_ipproto);
++      if (fd < 0)
++              error(1, errno, "socket");
++
++      if (cfg_proto == SOCK_STREAM) {
++              if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
++                             (char*) &val, sizeof(val)))
++                      error(1, 0, "setsockopt no nagle");
++
++              if (family == PF_INET) {
++                      if (connect(fd, (void *) &daddr, sizeof(daddr)))
++                              error(1, errno, "connect ipv4");
++              } else {
++                      if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
++                              error(1, errno, "connect ipv6");
++              }
++      }
++
++      if (cfg_do_pktinfo) {
++              if (family == AF_INET6) {
++                      if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO,
++                                     &val, sizeof(val)))
++                              error(1, errno, "setsockopt pktinfo ipv6");
++              } else {
++                      if (setsockopt(fd, SOL_IP, IP_PKTINFO,
++                                     &val, sizeof(val)))
++                              error(1, errno, "setsockopt pktinfo ipv4");
++              }
++      }
++
++      opt |= SOF_TIMESTAMPING_SOFTWARE |
++             SOF_TIMESTAMPING_OPT_CMSG |
++             SOF_TIMESTAMPING_OPT_ID;
++      if (cfg_loop_nodata)
++              opt |= SOF_TIMESTAMPING_OPT_TSONLY;
++
++      if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
++                     (char *) &opt, sizeof(opt)))
++              error(1, 0, "setsockopt timestamping");
++
++      for (i = 0; i < cfg_num_pkts; i++) {
++              memset(&ts_prev, 0, sizeof(ts_prev));
++              memset(buf, 'a' + i, total_len);
++
++              if (cfg_proto == SOCK_RAW) {
++                      struct udphdr *udph;
++                      int off = 0;
++
++                      if (cfg_ipproto == IPPROTO_RAW) {
++                              struct iphdr *iph = (void *) buf;
++
++                              memset(iph, 0, sizeof(*iph));
++                              iph->ihl      = 5;
++                              iph->version  = 4;
++                              iph->ttl      = 2;
++                              iph->daddr    = daddr.sin_addr.s_addr;
++                              iph->protocol = IPPROTO_UDP;
++                              /* kernel writes saddr, csum, len */
++
++                              off = sizeof(*iph);
++                      }
++
++                      udph = (void *) buf + off;
++                      udph->source = ntohs(9000);     /* random spoof */
++                      udph->dest   = ntohs(dest_port);
++                      udph->len    = ntohs(sizeof(*udph) + cfg_payload_len);
++                      udph->check  = 0;       /* not allowed for IPv6 */
++              }
++
++              print_timestamp_usr();
++              if (cfg_proto != SOCK_STREAM) {
++                      if (family == PF_INET)
++                              val = sendto(fd, buf, total_len, 0, (void *) &daddr, sizeof(daddr));
++                      else
++                              val = sendto(fd, buf, total_len, 0, (void *) &daddr6, sizeof(daddr6));
++              } else {
++                      val = send(fd, buf, cfg_payload_len, 0);
++              }
++              if (val != total_len)
++                      error(1, errno, "send");
++
++              /* wait for all errors to be queued, else ACKs arrive OOO */
++              usleep(50 * 1000);
++
++              __poll(fd);
++
++              while (!recv_errmsg(fd)) {}
++      }
++
++      if (close(fd))
++              error(1, errno, "close");
++
++      free(buf);
++      usleep(400 * 1000);
++}
++
++static void __attribute__((noreturn)) usage(const char *filepath)
++{
++      fprintf(stderr, "\nUsage: %s [options] hostname\n"
++                      "\nwhere options are:\n"
++                      "  -4:   only IPv4\n"
++                      "  -6:   only IPv6\n"
++                      "  -h:   show this message\n"
++                      "  -I:   request PKTINFO\n"
++                      "  -l N: send N bytes at a time\n"
++                      "  -n:   set no-payload option\n"
++                      "  -r:   use raw\n"
++                      "  -R:   use raw (IP_HDRINCL)\n"
++                      "  -p N: connect to port N\n"
++                      "  -u:   use udp\n"
++                      "  -x:   show payload (up to 70 bytes)\n",
++                      filepath);
++      exit(1);
++}
++
++static void parse_opt(int argc, char **argv)
++{
++      int proto_count = 0;
++      char c;
++
++      while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) {
++              switch (c) {
++              case '4':
++                      do_ipv6 = 0;
++                      break;
++              case '6':
++                      do_ipv4 = 0;
++                      break;
++              case 'I':
++                      cfg_do_pktinfo = true;
++                      break;
++              case 'n':
++                      cfg_loop_nodata = true;
++                      break;
++              case 'r':
++                      proto_count++;
++                      cfg_proto = SOCK_RAW;
++                      cfg_ipproto = IPPROTO_UDP;
++                      break;
++              case 'R':
++                      proto_count++;
++                      cfg_proto = SOCK_RAW;
++                      cfg_ipproto = IPPROTO_RAW;
++                      break;
++              case 'u':
++                      proto_count++;
++                      cfg_proto = SOCK_DGRAM;
++                      cfg_ipproto = IPPROTO_UDP;
++                      break;
++              case 'l':
++                      cfg_payload_len = strtoul(optarg, NULL, 10);
++                      break;
++              case 'p':
++                      dest_port = strtoul(optarg, NULL, 10);
++                      break;
++              case 'x':
++                      cfg_show_payload = true;
++                      break;
++              case 'h':
++              default:
++                      usage(argv[0]);
++              }
++      }
++
++      if (!cfg_payload_len)
++              error(1, 0, "payload may not be nonzero");
++      if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
++              error(1, 0, "udp packet might exceed expected MTU");
++      if (!do_ipv4 && !do_ipv6)
++              error(1, 0, "pass -4 or -6, not both");
++      if (proto_count > 1)
++              error(1, 0, "pass -r, -R or -u, not multiple");
++
++      if (optind != argc - 1)
++              error(1, 0, "missing required hostname argument");
++}
++
++static void resolve_hostname(const char *hostname)
++{
++      struct addrinfo *addrs, *cur;
++      int have_ipv4 = 0, have_ipv6 = 0;
++
++      if (getaddrinfo(hostname, NULL, NULL, &addrs))
++              error(1, errno, "getaddrinfo");
++
++      cur = addrs;
++      while (cur && !have_ipv4 && !have_ipv6) {
++              if (!have_ipv4 && cur->ai_family == AF_INET) {
++                      memcpy(&daddr, cur->ai_addr, sizeof(daddr));
++                      daddr.sin_port = htons(dest_port);
++                      have_ipv4 = 1;
++              }
++              else if (!have_ipv6 && cur->ai_family == AF_INET6) {
++                      memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
++                      daddr6.sin6_port = htons(dest_port);
++                      have_ipv6 = 1;
++              }
++              cur = cur->ai_next;
++      }
++      if (addrs)
++              freeaddrinfo(addrs);
++
++      do_ipv4 &= have_ipv4;
++      do_ipv6 &= have_ipv6;
++}
++
++static void do_main(int family)
++{
++      fprintf(stderr, "family:       %s\n",
++                      family == PF_INET ? "INET" : "INET6");
++
++      fprintf(stderr, "test SND\n");
++      do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
++
++      fprintf(stderr, "test ENQ\n");
++      do_test(family, SOF_TIMESTAMPING_TX_SCHED);
++
++      fprintf(stderr, "test ENQ + SND\n");
++      do_test(family, SOF_TIMESTAMPING_TX_SCHED |
++                      SOF_TIMESTAMPING_TX_SOFTWARE);
++
++      if (cfg_proto == SOCK_STREAM) {
++              fprintf(stderr, "\ntest ACK\n");
++              do_test(family, SOF_TIMESTAMPING_TX_ACK);
++
++              fprintf(stderr, "\ntest SND + ACK\n");
++              do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
++                              SOF_TIMESTAMPING_TX_ACK);
++
++              fprintf(stderr, "\ntest ENQ + SND + ACK\n");
++              do_test(family, SOF_TIMESTAMPING_TX_SCHED |
++                              SOF_TIMESTAMPING_TX_SOFTWARE |
++                              SOF_TIMESTAMPING_TX_ACK);
++      }
++}
++
++const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
++
++int main(int argc, char **argv)
++{
++      if (argc == 1)
++              usage(argv[0]);
++
++      parse_opt(argc, argv);
++      resolve_hostname(argv[argc - 1]);
++
++      fprintf(stderr, "protocol:     %s\n", sock_names[cfg_proto]);
++      fprintf(stderr, "payload:      %u\n", cfg_payload_len);
++      fprintf(stderr, "server port:  %u\n", dest_port);
++      fprintf(stderr, "\n");
++
++      if (do_ipv4)
++              do_main(PF_INET);
++      if (do_ipv6)
++              do_main(PF_INET6);
++
++      return 0;
++}
index d0beb496b8af73c43d4b3d2720ad7315df0720df..b82557a6ab11647f8004467a5f6e151a484ccad6 100644 (file)
@@ -84,3 +84,5 @@ proc-do-not-access-cmdline-nor-environ-from-file-backed-areas.patch
 media-dvb-frontends-fix-i2c-access-helpers-for-kasan.patch
 matroxfb-fix-size-of-memcpy.patch
 staging-speakup-replace-strncpy-with-memcpy.patch
+rocker-fix-rocker_tlv_put_-functions-for-kasan.patch
+selftests-move-networking-timestamping-from-documentation.patch