socket: Add SO_TIMESTAMPING_NEW

Add SO_TIMESTAMPING_NEW variant of socket timestamp options.
This is the y2038 safe versions of the SO_TIMESTAMPING_OLD
for all architectures.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Cc: chris@zankel.net
Cc: fenghua.yu@intel.com
Cc: rth@twiddle.net
Cc: tglx@linutronix.de
Cc: ubraun@linux.ibm.com
Cc: linux-alpha@vger.kernel.org
Cc: linux-arch@vger.kernel.org
Cc: linux-ia64@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: linux-s390@vger.kernel.org
Cc: linux-xtensa@linux-xtensa.org
Cc: sparclinux@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Deepa Dinamani 2019-02-02 07:34:51 -08:00 committed by David S. Miller
parent 887feae36a
commit 9718475e69
12 changed files with 88 additions and 30 deletions

View File

@ -117,19 +117,20 @@
#define SO_TIMESTAMP_NEW 63 #define SO_TIMESTAMP_NEW 63
#define SO_TIMESTAMPNS_NEW 64 #define SO_TIMESTAMPNS_NEW 64
#define SO_TIMESTAMPING_NEW 65
#if !defined(__KERNEL__) #if !defined(__KERNEL__)
#if __BITS_PER_LONG == 64 #if __BITS_PER_LONG == 64
#define SO_TIMESTAMP SO_TIMESTAMP_OLD #define SO_TIMESTAMP SO_TIMESTAMP_OLD
#define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD #define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#else #else
#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW) #define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW) #define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
#endif #endif
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#define SCM_TIMESTAMP SO_TIMESTAMP #define SCM_TIMESTAMP SO_TIMESTAMP
#define SCM_TIMESTAMPNS SO_TIMESTAMPNS #define SCM_TIMESTAMPNS SO_TIMESTAMPNS
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING

View File

@ -128,19 +128,20 @@
#define SO_TIMESTAMP_NEW 63 #define SO_TIMESTAMP_NEW 63
#define SO_TIMESTAMPNS_NEW 64 #define SO_TIMESTAMPNS_NEW 64
#define SO_TIMESTAMPING_NEW 65
#if !defined(__KERNEL__) #if !defined(__KERNEL__)
#if __BITS_PER_LONG == 64 #if __BITS_PER_LONG == 64
#define SO_TIMESTAMP SO_TIMESTAMP_OLD #define SO_TIMESTAMP SO_TIMESTAMP_OLD
#define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD #define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#else #else
#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW) #define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW) #define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
#endif #endif
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#define SCM_TIMESTAMP SO_TIMESTAMP #define SCM_TIMESTAMP SO_TIMESTAMP
#define SCM_TIMESTAMPNS SO_TIMESTAMPNS #define SCM_TIMESTAMPNS SO_TIMESTAMPNS
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING

View File

@ -109,19 +109,20 @@
#define SO_TIMESTAMP_NEW 0x4038 #define SO_TIMESTAMP_NEW 0x4038
#define SO_TIMESTAMPNS_NEW 0x4039 #define SO_TIMESTAMPNS_NEW 0x4039
#define SO_TIMESTAMPING_NEW 0x403A
#if !defined(__KERNEL__) #if !defined(__KERNEL__)
#if __BITS_PER_LONG == 64 #if __BITS_PER_LONG == 64
#define SO_TIMESTAMP SO_TIMESTAMP_OLD #define SO_TIMESTAMP SO_TIMESTAMP_OLD
#define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD #define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#else #else
#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW) #define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW) #define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
#endif #endif
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#define SCM_TIMESTAMP SO_TIMESTAMP #define SCM_TIMESTAMP SO_TIMESTAMP
#define SCM_TIMESTAMPNS SO_TIMESTAMPNS #define SCM_TIMESTAMPNS SO_TIMESTAMPNS
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING

View File

@ -110,19 +110,20 @@
#define SO_TIMESTAMP_NEW 0x0041 #define SO_TIMESTAMP_NEW 0x0041
#define SO_TIMESTAMPNS_NEW 0x0042 #define SO_TIMESTAMPNS_NEW 0x0042
#define SO_TIMESTAMPING_NEW 0x0043
#if !defined(__KERNEL__) #if !defined(__KERNEL__)
#if __BITS_PER_LONG == 64 #if __BITS_PER_LONG == 64
#define SO_TIMESTAMP SO_TIMESTAMP_OLD #define SO_TIMESTAMP SO_TIMESTAMP_OLD
#define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD #define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#else #else
#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW) #define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW) #define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
#endif #endif
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#define SCM_TIMESTAMP SO_TIMESTAMP #define SCM_TIMESTAMP SO_TIMESTAMP
#define SCM_TIMESTAMPNS SO_TIMESTAMPNS #define SCM_TIMESTAMPNS SO_TIMESTAMPNS
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING

View File

@ -349,9 +349,17 @@ struct ucred {
extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
struct timespec64;
struct __kernel_timespec; struct __kernel_timespec;
struct old_timespec32; struct old_timespec32;
struct scm_timestamping_internal {
struct timespec64 ts[3];
};
extern void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss);
extern void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss);
/* The __sys_...msg variants allow MSG_CMSG_COMPAT iff /* The __sys_...msg variants allow MSG_CMSG_COMPAT iff
* forbid_cmsg_compat==false * forbid_cmsg_compat==false
*/ */

View File

@ -112,6 +112,7 @@
#define SO_TIMESTAMP_NEW 63 #define SO_TIMESTAMP_NEW 63
#define SO_TIMESTAMPNS_NEW 64 #define SO_TIMESTAMPNS_NEW 64
#define SO_TIMESTAMPING_NEW 65
#if !defined(__KERNEL__) #if !defined(__KERNEL__)
@ -119,13 +120,13 @@
/* on 64-bit and x32, avoid the ?: operator */ /* on 64-bit and x32, avoid the ?: operator */
#define SO_TIMESTAMP SO_TIMESTAMP_OLD #define SO_TIMESTAMP SO_TIMESTAMP_OLD
#define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD #define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#else #else
#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW) #define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW) #define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
#endif #endif
#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
#define SCM_TIMESTAMP SO_TIMESTAMP #define SCM_TIMESTAMP SO_TIMESTAMP
#define SCM_TIMESTAMPNS SO_TIMESTAMPNS #define SCM_TIMESTAMPNS SO_TIMESTAMPNS
#define SCM_TIMESTAMPING SO_TIMESTAMPING #define SCM_TIMESTAMPING SO_TIMESTAMPING

View File

@ -41,6 +41,10 @@ struct scm_timestamping {
struct timespec ts[3]; struct timespec ts[3];
}; };
struct scm_timestamping64 {
struct __kernel_timespec ts[3];
};
/* The type of scm_timestamping, passed in sock_extended_err ee_info. /* The type of scm_timestamping, passed in sock_extended_err ee_info.
* This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0] * This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0]
* is zero, then this is a hardware timestamp and recorded in ts[2]. * is zero, then this is a hardware timestamp and recorded in ts[2].

View File

@ -29,6 +29,7 @@
#include <linux/pid.h> #include <linux/pid.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/errqueue.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
@ -252,6 +253,32 @@ out:
} }
EXPORT_SYMBOL(put_cmsg); EXPORT_SYMBOL(put_cmsg);
void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss_internal)
{
struct scm_timestamping64 tss;
int i;
for (i = 0; i < ARRAY_SIZE(tss.ts); i++) {
tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec;
tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec;
}
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_NEW, sizeof(tss), &tss);
}
EXPORT_SYMBOL(put_cmsg_scm_timestamping64);
void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss_internal)
{
struct scm_timestamping tss;
int i;
for (i = 0; i < ARRAY_SIZE(tss.ts); i++)
tss.ts[i] = timespec64_to_timespec(tss_internal->ts[i]);
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, sizeof(tss), &tss);
}
EXPORT_SYMBOL(put_cmsg_scm_timestamping);
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
{ {
struct cmsghdr __user *cm struct cmsghdr __user *cm

View File

@ -890,6 +890,8 @@ set_rcvbuf:
} }
break; break;
case SO_TIMESTAMPING_NEW:
sock_set_flag(sk, SOCK_TSTAMP_NEW);
case SO_TIMESTAMPING_OLD: case SO_TIMESTAMPING_OLD:
if (val & ~SOF_TIMESTAMPING_MASK) { if (val & ~SOF_TIMESTAMPING_MASK) {
ret = -EINVAL; ret = -EINVAL;
@ -921,9 +923,13 @@ set_rcvbuf:
if (val & SOF_TIMESTAMPING_RX_SOFTWARE) if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
sock_enable_timestamp(sk, sock_enable_timestamp(sk,
SOCK_TIMESTAMPING_RX_SOFTWARE); SOCK_TIMESTAMPING_RX_SOFTWARE);
else else {
if (optname == SO_TIMESTAMPING_NEW)
sock_reset_flag(sk, SOCK_TSTAMP_NEW);
sock_disable_timestamp(sk, sock_disable_timestamp(sk,
(1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE));
}
break; break;
case SO_RCVLOWAT: case SO_RCVLOWAT:

View File

@ -1844,22 +1844,22 @@ out:
#endif #endif
static void tcp_update_recv_tstamps(struct sk_buff *skb, static void tcp_update_recv_tstamps(struct sk_buff *skb,
struct scm_timestamping *tss) struct scm_timestamping_internal *tss)
{ {
if (skb->tstamp) if (skb->tstamp)
tss->ts[0] = ktime_to_timespec(skb->tstamp); tss->ts[0] = ktime_to_timespec64(skb->tstamp);
else else
tss->ts[0] = (struct timespec) {0}; tss->ts[0] = (struct timespec64) {0};
if (skb_hwtstamps(skb)->hwtstamp) if (skb_hwtstamps(skb)->hwtstamp)
tss->ts[2] = ktime_to_timespec(skb_hwtstamps(skb)->hwtstamp); tss->ts[2] = ktime_to_timespec64(skb_hwtstamps(skb)->hwtstamp);
else else
tss->ts[2] = (struct timespec) {0}; tss->ts[2] = (struct timespec64) {0};
} }
/* Similar to __sock_recv_timestamp, but does not require an skb */ /* Similar to __sock_recv_timestamp, but does not require an skb */
static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk, static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
struct scm_timestamping *tss) struct scm_timestamping_internal *tss)
{ {
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
bool has_timestamping = false; bool has_timestamping = false;
@ -1873,8 +1873,10 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW, put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
sizeof(kts), &kts); sizeof(kts), &kts);
} else { } else {
struct timespec ts_old = timespec64_to_timespec(tss->ts[0]);
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD, put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
sizeof(tss->ts[0]), &tss->ts[0]); sizeof(ts_old), &ts_old);
} }
} else { } else {
if (new_tstamp) { if (new_tstamp) {
@ -1898,20 +1900,22 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
has_timestamping = true; has_timestamping = true;
else else
tss->ts[0] = (struct timespec) {0}; tss->ts[0] = (struct timespec64) {0};
} }
if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) { if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)
has_timestamping = true; has_timestamping = true;
else else
tss->ts[2] = (struct timespec) {0}; tss->ts[2] = (struct timespec64) {0};
} }
if (has_timestamping) { if (has_timestamping) {
tss->ts[1] = (struct timespec) {0}; tss->ts[1] = (struct timespec64) {0};
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, if (sock_flag(sk, SOCK_TSTAMP_NEW))
sizeof(*tss), tss); put_cmsg_scm_timestamping64(msg, tss);
else
put_cmsg_scm_timestamping(msg, tss);
} }
} }
@ -1952,7 +1956,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
long timeo; long timeo;
struct sk_buff *skb, *last; struct sk_buff *skb, *last;
u32 urg_hole = 0; u32 urg_hole = 0;
struct scm_timestamping tss; struct scm_timestamping_internal tss;
bool has_tss = false; bool has_tss = false;
bool has_cmsg; bool has_cmsg;

View File

@ -291,7 +291,8 @@ static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk,
(1UL << SOCK_RXQ_OVFL) | \ (1UL << SOCK_RXQ_OVFL) | \
(1UL << SOCK_WIFI_STATUS) | \ (1UL << SOCK_WIFI_STATUS) | \
(1UL << SOCK_NOFCS) | \ (1UL << SOCK_NOFCS) | \
(1UL << SOCK_FILTER_LOCKED)) (1UL << SOCK_FILTER_LOCKED) | \
(1UL << SOCK_TSTAMP_NEW))
/* copy only relevant settings and flags of SOL_SOCKET level from smc to /* copy only relevant settings and flags of SOL_SOCKET level from smc to
* clc socket (since smc is not called for these options from net/core) * clc socket (since smc is not called for these options from net/core)
*/ */

View File

@ -706,7 +706,8 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
{ {
int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
struct scm_timestamping tss; struct scm_timestamping_internal tss;
int empty = 1, false_tstamp = 0; int empty = 1, false_tstamp = 0;
struct skb_shared_hwtstamps *shhwtstamps = struct skb_shared_hwtstamps *shhwtstamps =
skb_hwtstamps(skb); skb_hwtstamps(skb);
@ -752,20 +753,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
memset(&tss, 0, sizeof(tss)); memset(&tss, 0, sizeof(tss));
if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) && if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0))
empty = 0; empty = 0;
if (shhwtstamps && if (shhwtstamps &&
(sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
!skb_is_swtx_tstamp(skb, false_tstamp) && !skb_is_swtx_tstamp(skb, false_tstamp) &&
ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) { ktime_to_timespec64_cond(shhwtstamps->hwtstamp, tss.ts + 2)) {
empty = 0; empty = 0;
if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) && if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&
!skb_is_err_queue(skb)) !skb_is_err_queue(skb))
put_ts_pktinfo(msg, skb); put_ts_pktinfo(msg, skb);
} }
if (!empty) { if (!empty) {
put_cmsg(msg, SOL_SOCKET, if (sock_flag(sk, SOCK_TSTAMP_NEW))
SO_TIMESTAMPING_OLD, sizeof(tss), &tss); put_cmsg_scm_timestamping64(msg, &tss);
else
put_cmsg_scm_timestamping(msg, &tss);
if (skb_is_err_queue(skb) && skb->len && if (skb_is_err_queue(skb) && skb->len &&
SKB_EXT_ERR(skb)->opt_stats) SKB_EXT_ERR(skb)->opt_stats)