net: fix SOF_TIMESTAMPING_BIND_PHC to work with multiple sockets
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 5 Jan 2022 10:33:26 +0000 (11:33 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 6 Jan 2022 12:18:08 +0000 (12:18 +0000)
When multiple sockets using the SOF_TIMESTAMPING_BIND_PHC flag received
a packet with a hardware timestamp (e.g. multiple PTP instances in
different PTP domains using the UDPv4/v6 multicast or L2 transport),
the timestamps received on some sockets were corrupted due to repeated
conversion of the same timestamp (by the same or different vclocks).

Fix ptp_convert_timestamp() to not modify the shared skb timestamp
and return the converted timestamp as a ktime_t instead. If the
conversion fails, return 0 to not confuse the application with
timestamps corresponding to an unexpected PHC.

Fixes: d7c088265588 ("net: socket: support hardware timestamp conversion to PHC bound")
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
Cc: Yangbo Lu <yangbo.lu@nxp.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/ptp/ptp_vclock.c
include/linux/ptp_clock_kernel.h
net/socket.c

index baee037..ab1d233 100644 (file)
@@ -185,8 +185,8 @@ out:
 }
 EXPORT_SYMBOL(ptp_get_vclocks_index);
 
-void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps,
-                          int vclock_index)
+ktime_t ptp_convert_timestamp(const struct skb_shared_hwtstamps *hwtstamps,
+                             int vclock_index)
 {
        char name[PTP_CLOCK_NAME_LEN] = "";
        struct ptp_vclock *vclock;
@@ -198,12 +198,12 @@ void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps,
        snprintf(name, PTP_CLOCK_NAME_LEN, "ptp%d", vclock_index);
        dev = class_find_device_by_name(ptp_class, name);
        if (!dev)
-               return;
+               return 0;
 
        ptp = dev_get_drvdata(dev);
        if (!ptp->is_virtual_clock) {
                put_device(dev);
-               return;
+               return 0;
        }
 
        vclock = info_to_vclock(ptp->info);
@@ -215,7 +215,7 @@ void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps,
        spin_unlock_irqrestore(&vclock->lock, flags);
 
        put_device(dev);
-       hwtstamps->hwtstamp = ns_to_ktime(ns);
+       return ns_to_ktime(ns);
 }
 EXPORT_SYMBOL(ptp_convert_timestamp);
 #endif
index 2e55650..554454c 100644 (file)
@@ -351,15 +351,17 @@ int ptp_get_vclocks_index(int pclock_index, int **vclock_index);
  *
  * @hwtstamps:    skb_shared_hwtstamps structure pointer
  * @vclock_index: phc index of ptp vclock.
+ *
+ * Returns converted timestamp, or 0 on error.
  */
-void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps,
-                          int vclock_index);
+ktime_t ptp_convert_timestamp(const struct skb_shared_hwtstamps *hwtstamps,
+                             int vclock_index);
 #else
 static inline int ptp_get_vclocks_index(int pclock_index, int **vclock_index)
 { return 0; }
-static inline void ptp_convert_timestamp(struct skb_shared_hwtstamps *hwtstamps,
-                                        int vclock_index)
-{ }
+static inline ktime_t ptp_convert_timestamp(const struct skb_shared_hwtstamps *hwtstamps,
+                                           int vclock_index)
+{ return 0; }
 
 #endif
 
index 5e644c8..50cf757 100644 (file)
@@ -830,6 +830,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        int empty = 1, false_tstamp = 0;
        struct skb_shared_hwtstamps *shhwtstamps =
                skb_hwtstamps(skb);
+       ktime_t hwtstamp;
 
        /* Race occurred between timestamp enabling and packet
           receiving.  Fill in the current time for now. */
@@ -878,10 +879,12 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
            (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
            !skb_is_swtx_tstamp(skb, false_tstamp)) {
                if (sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC)
-                       ptp_convert_timestamp(shhwtstamps, sk->sk_bind_phc);
+                       hwtstamp = ptp_convert_timestamp(shhwtstamps,
+                                                        sk->sk_bind_phc);
+               else
+                       hwtstamp = shhwtstamps->hwtstamp;
 
-               if (ktime_to_timespec64_cond(shhwtstamps->hwtstamp,
-                                            tss.ts + 2)) {
+               if (ktime_to_timespec64_cond(hwtstamp, tss.ts + 2)) {
                        empty = 0;
 
                        if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&