*/
        if (sock_flag(sk, SOCK_RCVTSTAMP) ||
            sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) ||
-           (kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) ||
+           (kt.tv64 &&
+            (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) ||
+             skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP)) ||
            (hwtstamps->hwtstamp.tv64 &&
             sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)))
                __sock_recv_timestamp(msg, sk, skb);
 
 
 #define SO_EE_OFFENDER(ee)     ((struct sockaddr*)((ee)+1))
 
+/**
+ *     struct scm_timestamping - timestamps exposed through cmsg
+ *
+ *     The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_*
+ *     communicate network timestamps by passing this struct in a cmsg with
+ *     recvmsg(). See Documentation/networking/timestamping.txt for details.
+ */
+struct scm_timestamping {
+       struct timespec ts[3];
+};
+
+/* 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]
+ * is zero, then this is a hardware timestamp and recorded in ts[2].
+ */
+enum {
+       SCM_TSTAMP_SND,         /* driver passed skb to NIC, or HW */
+};
 
 #endif /* _UAPI_LINUX_ERRQUEUE_H */
 
 #include <linux/sockios.h>
 #include <linux/atalk.h>
 #include <net/busy_poll.h>
+#include <linux/errqueue.h>
 
 #ifdef CONFIG_NET_RX_BUSY_POLL
 unsigned int sysctl_net_busy_read __read_mostly;
        struct sk_buff *skb)
 {
        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
-       struct timespec ts[3];
+       struct scm_timestamping tss;
        int empty = 1;
        struct skb_shared_hwtstamps *shhwtstamps =
                skb_hwtstamps(skb);
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
                                 sizeof(tv), &tv);
                } else {
-                       skb_get_timestampns(skb, &ts[0]);
+                       struct timespec ts;
+                       skb_get_timestampns(skb, &ts);
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
-                                sizeof(ts[0]), &ts[0]);
+                                sizeof(ts), &ts);
                }
        }
 
-
-       memset(ts, 0, sizeof(ts));
-       if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) &&
-           ktime_to_timespec_cond(skb->tstamp, ts + 0))
+       memset(&tss, 0, sizeof(tss));
+       if ((sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) ||
+            skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) &&
+           ktime_to_timespec_cond(skb->tstamp, tss.ts + 0))
                empty = 0;
        if (shhwtstamps &&
            sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) &&
-           ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2))
+           ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2))
                empty = 0;
        if (!empty)
                put_cmsg(msg, SOL_SOCKET,
-                        SCM_TIMESTAMPING, sizeof(ts), &ts);
+                        SCM_TIMESTAMPING, sizeof(tss), &tss);
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);