option IP_PKTINFO simultaneously.
 
 
+SOF_TIMESTAMPING_OPT_TSONLY:
+
+  Applies to transmit timestamps only. Makes the kernel return the
+  timestamp as a cmsg alongside an empty packet, as opposed to
+  alongside the original packet. This reduces the amount of memory
+  charged to the socket's receive budget (SO_RCVBUF) and delivers
+  the timestamp even if sysctl net.core.tstamp_allow_data is 0.
+  This option disables SOF_TIMESTAMPING_OPT_CMSG.
+
+
+New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to
+disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate
+regardless of the setting of sysctl net.core.tstamp_allow_data.
+
+An exception is when a process needs additional cmsg data, for
+instance SOL_IP/IP_PKTINFO to detect the egress network interface.
+Then pass option SOF_TIMESTAMPING_OPT_CMSG. This option depends on
+having access to the contents of the original packet, so cannot be
+combined with SOF_TIMESTAMPING_OPT_TSONLY.
+
+
 1.4 Bytestream Timestamps
 
 The SO_TIMESTAMPING interface supports timestamping of bytes in a
 
        SOF_TIMESTAMPING_TX_SCHED = (1<<8),
        SOF_TIMESTAMPING_TX_ACK = (1<<9),
        SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
+       SOF_TIMESTAMPING_OPT_TSONLY = (1<<11),
 
-       SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_CMSG,
+       SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TSONLY,
        SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
                                 SOF_TIMESTAMPING_LAST
 };
 
                     struct sock *sk, int tstype)
 {
        struct sk_buff *skb;
+       bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
 
        if (!sk)
                return;
 
-       if (hwtstamps)
-               *skb_hwtstamps(orig_skb) = *hwtstamps;
+       if (tsonly)
+               skb = alloc_skb(0, GFP_ATOMIC);
        else
-               orig_skb->tstamp = ktime_get_real();
-
-       skb = skb_clone(orig_skb, GFP_ATOMIC);
+               skb = skb_clone(orig_skb, GFP_ATOMIC);
        if (!skb)
                return;
 
+       if (tsonly) {
+               skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags;
+               skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey;
+       }
+
+       if (hwtstamps)
+               *skb_hwtstamps(skb) = *hwtstamps;
+       else
+               skb->tstamp = ktime_get_real();
+
        __skb_complete_tx_timestamp(skb, sk, tstype);
 }
 EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
 
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin) {
+       if (sin && skb->len) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
                                                   serr->addr_offset);
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
 
-       if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
-           ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) {
+       if (skb->len &&
+           (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
+            ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
                if (inet_sk(sk)->cmsg_flags)
 
 
        serr = SKB_EXT_ERR(skb);
 
-       if (sin) {
+       if (sin && skb->len) {
                const unsigned char *nh = skb_network_header(skb);
                sin->sin6_family = AF_INET6;
                sin->sin6_flowinfo = 0;
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
        memset(sin, 0, sizeof(*sin));
-
-       if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
+       if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) {
                sin->sin6_family = AF_INET6;
                if (np->rxopt.all) {
                        if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
 
                _leave("UDP socket errqueue empty");
                return;
        }
+       if (!skb->len) {
+               _leave("UDP empty message");
+               kfree_skb(skb);
+               return;
+       }
 
        rxrpc_new_skb(skb);