Subject: [PATCH 3/8] socket: Disentangle SOCK_RCVTSTAMPNS from SOCK_RCVTSTAMP

From: Deepa Dinamani <[email-masked]>
Date: Fri, 23 Nov 2018 18:20:30 -0800

SOCK_RCVTSTAMPNS is never set alone. SOCK_RCVTSTAMP
is always set along with SOCK_RCVTSTAMPNS. This leads to
checking for two flag states whenever we need to check for
SOCK_RCVTSTAMPS.

Also SOCK_RCVTSTAMPS was the only flag that needed to be
checked in order to verify if either of the two flags are
set. But, the two features are not actually dependent on
each other. This artificial dependency creates more
confusion.
The change does away with this logic as well.

Note that RDS seems to be supporting only SO_TIMESTAMP at
SOL_RDS level. And, it uses the same SOCK_RCVTSTAMP to track
this. Hence, the updates to rds_incoming->i_rx_tstamp only
track SOCK_RCVTSTAMP and not SOCK_RCVTSTAMPNS.

Signed-off-by: Deepa Dinamani <[email-masked]>
---
 include/net/sock.h |  4 +++-
 net/core/sock.c    | 37 ++++++++++++++++++++++++-------------
 net/ipv4/tcp.c     | 20 +++++++++-----------
 net/socket.c       |  3 ++-
 net/unix/af_unix.c |  4 ++--
 5 files changed, 40 insertions(+), 28 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index f665d74ae509..8143c4c1a49d 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2305,6 +2305,7 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 	 * - hardware time stamps available and wanted
 	 */
 	if (sock_flag(sk, SOCK_RCVTSTAMP) ||
+		sock_flag(sk, SOCK_RCVTSTAMPNS) ||
 	    (sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE) ||
 	    (kt && sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) ||
 	    (hwtstamps->hwtstamp &&
@@ -2325,7 +2326,8 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
 					  struct sk_buff *skb)
 {
 #define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL)			| \
-			   (1UL << SOCK_RCVTSTAMP))
+			   (1UL << SOCK_RCVTSTAMP)			| \
+			   (1UL << SOCK_RCVTSTAMPNS))
 #define TSFLAGS_ANY	  (SOF_TIMESTAMPING_SOFTWARE			| \
 			   SOF_TIMESTAMPING_RAW_HARDWARE)
 
diff --git a/net/core/sock.c b/net/core/sock.c
index cf990db9b2a0..e60036618205 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -647,6 +647,28 @@ bool sk_mc_loop(struct sock *sk)
 }
 EXPORT_SYMBOL(sk_mc_loop);
 
+static void setsockopt_timestamp(struct sock *sk, int type, int val)
+{
+	if (!val) {
+		sock_reset_flag(sk, SOCK_RCVTSTAMP);
+		sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+		return;
+	}
+
+	switch (type) {
+	case SO_TIMESTAMP_OLD:
+		sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+		sock_set_flag(sk, SOCK_RCVTSTAMP);
+		break;
+	case SO_TIMESTAMPNS_OLD:
+		sock_reset_flag(sk, SOCK_RCVTSTAMP);
+		sock_set_flag(sk, SOCK_RCVTSTAMPNS);
+		break;
+	}
+
+	sock_enable_timestamp(sk, SOCK_TIMESTAMP);
+}
+
 /*
  *	This is meant for all protocols to use and covers goings on
  *	at the socket level. Everything here is generic.
@@ -816,17 +838,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
 
 	case SO_TIMESTAMP_OLD:
 	case SO_TIMESTAMPNS_OLD:
-		if (valbool)  {
-			if (optname == SO_TIMESTAMP_OLD)
-				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
-			else
-				sock_set_flag(sk, SOCK_RCVTSTAMPNS);
-			sock_set_flag(sk, SOCK_RCVTSTAMP);
-			sock_enable_timestamp(sk, SOCK_TIMESTAMP);
-		} else {
-			sock_reset_flag(sk, SOCK_RCVTSTAMP);
-			sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
-		}
+		setsockopt_timestamp(sk, optname, valbool);
 		break;
 
 	case SO_TIMESTAMPING_OLD:
@@ -1183,8 +1195,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 		break;
 
 	case SO_TIMESTAMP_OLD:
-		v.val = sock_flag(sk, SOCK_RCVTSTAMP) &&
-				!sock_flag(sk, SOCK_RCVTSTAMPNS);
+		v.val = sock_flag(sk, SOCK_RCVTSTAMP);
 		break;
 
 	case SO_TIMESTAMPNS_OLD:
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 496848ab0269..d6eb5f542fcf 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1868,17 +1868,15 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
 	bool has_timestamping = false;
 
 	if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) {
-		if (sock_flag(sk, SOCK_RCVTSTAMP)) {
-			if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
-				put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
-					 sizeof(tss->ts[0]), &tss->ts[0]);
-			} else {
-				tv.tv_sec = tss->ts[0].tv_sec;
-				tv.tv_usec = tss->ts[0].tv_nsec / 1000;
-
-				put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
-					 sizeof(tv), &tv);
-			}
+		if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
+			put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
+				 sizeof(tss->ts[0]), &tss->ts[0]);
+		} else if (sock_flag(sk, SOCK_RCVTSTAMP)) {
+			tv.tv_sec = tss->ts[0].tv_sec;
+			tv.tv_usec = tss->ts[0].tv_nsec / 1000;
+
+			put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
+				 sizeof(tv), &tv);
 		}
 
 		if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
diff --git a/net/socket.c b/net/socket.c
index dfc5742ccfbb..c7455349a3c1 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -701,11 +701,12 @@ static void put_ts_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 
 /*
  * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
+ * or sock_flag(sk, SOCK_RCVTSTAMPNS)
  */
 void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 	struct sk_buff *skb)
 {
-	int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
+	int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP) || sock_flag(sk, SOCK_RCVTSTAMPNS);
 	struct scm_timestamping tss;
 	int empty = 1, false_tstamp = 0;
 	struct skb_shared_hwtstamps *shhwtstamps =
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 74d1eed7cbd4..531efd0ddeb1 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1798,7 +1798,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 	if (unlikely(sk_locked))
 		unix_state_unlock(sk);
 
-	if (sock_flag(other, SOCK_RCVTSTAMP))
+	if (sock_flag(other, SOCK_RCVTSTAMP) || sock_flag(other, SOCK_RCVTSTAMPNS))
 		__net_timestamp(skb);
 	maybe_add_creds(skb, sock, other);
 	skb_queue_tail(&other->sk_receive_queue, skb);
@@ -2141,7 +2141,7 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
 	if (err)
 		goto out_free;
 
-	if (sock_flag(sk, SOCK_RCVTSTAMP))
+	if (sock_flag(sk, SOCK_RCVTSTAMP) || sock_flag(sk, SOCK_RCVTSTAMPNS))
 		__sock_recv_timestamp(msg, sk, skb);
 
 	memset(&scm, 0, sizeof(scm));
-- 
2.17.1