diff mbox series

[net,1/2] socket: fix option SO_TIMESTAMPING_NEW

Message ID 20201009103121.1004-1-ceggers@arri.de
State Changes Requested
Delegated to: David Miller
Headers show
Series [net,1/2] socket: fix option SO_TIMESTAMPING_NEW | expand

Commit Message

Christian Eggers Oct. 9, 2020, 10:31 a.m. UTC
The comparison of optname with SO_TIMESTAMPING_NEW is wrong way around,
so SOCK_TSTAMP_NEW will first be set and than reset again. Additionally
move it out of the test for SOF_TIMESTAMPING_RX_SOFTWARE as this seems
unrelated.

This problem happens on 32 bit platforms were the libc has already
switched to struct timespec64 (from SO_TIMExxx_OLD to SO_TIMExxx_NEW
socket options). ptp4l complains with "missing timestamp on transmitted
peer delay request" because the wrong format is received (and
discarded).

Fixes: 9718475e6908 ("socket: Add SO_TIMESTAMPING_NEW")
Signed-off-by: Christian Eggers <ceggers@arri.de>
---
 net/core/sock.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

Comments

Willem de Bruijn Oct. 10, 2020, 12:23 a.m. UTC | #1
On Fri, Oct 9, 2020 at 6:32 AM Christian Eggers <ceggers@arri.de> wrote:
>
> The comparison of optname with SO_TIMESTAMPING_NEW is wrong way around,
> so SOCK_TSTAMP_NEW will first be set and than reset again. Additionally
> move it out of the test for SOF_TIMESTAMPING_RX_SOFTWARE as this seems
> unrelated.
>
> This problem happens on 32 bit platforms were the libc has already
> switched to struct timespec64 (from SO_TIMExxx_OLD to SO_TIMExxx_NEW
> socket options). ptp4l complains with "missing timestamp on transmitted
> peer delay request" because the wrong format is received (and
> discarded).
>
> Fixes: 9718475e6908 ("socket: Add SO_TIMESTAMPING_NEW")
> Signed-off-by: Christian Eggers <ceggers@arri.de>
> ---
>  net/core/sock.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/net/core/sock.c b/net/core/sock.c
> index 34a8d12e38d7..3926804702c1 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1024,16 +1024,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
>                 }
>
>                 sk->sk_tsflags = val;
> +               if (optname != SO_TIMESTAMPING_NEW)
> +                       sock_reset_flag(sk, SOCK_TSTAMP_NEW);
> +
>                 if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
>                         sock_enable_timestamp(sk,
>                                               SOCK_TIMESTAMPING_RX_SOFTWARE);
> -               else {
> -                       if (optname == SO_TIMESTAMPING_NEW)
> -                               sock_reset_flag(sk, SOCK_TSTAMP_NEW);
> -

The idea is to select new vs old behavior depending on which of the
two setsockopts is called.

This suggested fix still sets and clears the flag if calling
SO_TIMESTAMPING_NEW to disable timestamping. Instead, how about

        case SO_TIMESTAMPING_NEW:
-               sock_set_flag(sk, SOCK_TSTAMP_NEW);
                fallthrough;
        case SO_TIMESTAMPING_OLD:
[..]
+               sock_valbool_flag(sk, SOCK_TSTAMP_NEW,
+                                 optname == SO_TIMESTAMPING_NEW);
+
                if (val & SOF_TIMESTAMPING_OPT_ID &&

That is a subtle behavioral change, because it now leaves
SOCK_TSTAMP_NEW set also when timestamping is turned off. But this is
harmless, as in that case the versioning does not matter. A more
pedantic version would be

+               sock_valbool_flag(sk, SOCK_TSTAMP_NEW,
+                                 optname == SO_TIMESTAMPING_NEW &&
+                                 val & SOF_TIMESTAMPING_TX_RECORD_MASK);
Deepa Dinamani Oct. 10, 2020, 12:30 a.m. UTC | #2
On Fri, Oct 9, 2020 at 3:32 AM Christian Eggers <ceggers@arri.de> wrote:
>
> The comparison of optname with SO_TIMESTAMPING_NEW is wrong way around,
> so SOCK_TSTAMP_NEW will first be set and than reset again. Additionally
> move it out of the test for SOF_TIMESTAMPING_RX_SOFTWARE as this seems
> unrelated.

The SOCK_TSTAMP_NEW is reset only in the case when
SOF_TIMESTAMPING_RX_SOFTWARE is not set.
Note that we only call sock_enable_timestamp() at that time.

Why would SOCK_TSTAMP_NEW be relevant otherwise?

-Deepa
Willem de Bruijn Oct. 10, 2020, 12:43 a.m. UTC | #3
On Fri, Oct 9, 2020 at 8:30 PM Deepa Dinamani <deepa.kernel@gmail.com> wrote:
>
> On Fri, Oct 9, 2020 at 3:32 AM Christian Eggers <ceggers@arri.de> wrote:
> >
> > The comparison of optname with SO_TIMESTAMPING_NEW is wrong way around,
> > so SOCK_TSTAMP_NEW will first be set and than reset again. Additionally
> > move it out of the test for SOF_TIMESTAMPING_RX_SOFTWARE as this seems
> > unrelated.
>
> The SOCK_TSTAMP_NEW is reset only in the case when
> SOF_TIMESTAMPING_RX_SOFTWARE is not set.
> Note that we only call sock_enable_timestamp() at that time.
>
> Why would SOCK_TSTAMP_NEW be relevant otherwise?

Other timestamps can be configured, such as hardware timestamps.

As the follow-on patch shows, there is also the issue of overlap
between SO_TIMESTAMP(NS) and SO_TIMESTAMPING.

Don't select OLD on timestamp disable, which may only disable
some of the ongoing timestamping.

Setting based on the syscall is simpler, too. __sock_set_timestamps
already uses for SO_TIMESTAMP(NS) the valbool approach I
suggest for SO_TIMESTAMPING.

The fallthrough can also be removed. My rough patch missed that.
Deepa Dinamani Oct. 10, 2020, 3:09 a.m. UTC | #4
On Fri, Oct 9, 2020 at 5:43 PM Willem de Bruijn <willemb@google.com> wrote:
>
> On Fri, Oct 9, 2020 at 8:30 PM Deepa Dinamani <deepa.kernel@gmail.com> wrote:
> >
> > On Fri, Oct 9, 2020 at 3:32 AM Christian Eggers <ceggers@arri.de> wrote:
> > >
> > > The comparison of optname with SO_TIMESTAMPING_NEW is wrong way around,
> > > so SOCK_TSTAMP_NEW will first be set and than reset again. Additionally
> > > move it out of the test for SOF_TIMESTAMPING_RX_SOFTWARE as this seems
> > > unrelated.
> >
> > The SOCK_TSTAMP_NEW is reset only in the case when
> > SOF_TIMESTAMPING_RX_SOFTWARE is not set.
> > Note that we only call sock_enable_timestamp() at that time.
> >
> > Why would SOCK_TSTAMP_NEW be relevant otherwise?
>
> Other timestamps can be configured, such as hardware timestamps.
>
> As the follow-on patch shows, there is also the issue of overlap
> between SO_TIMESTAMP(NS) and SO_TIMESTAMPING.

I see. Thanks for clarification. I think I had missed that you could
have both software and hardware timestamps enabled at the same time.

> Don't select OLD on timestamp disable, which may only disable
> some of the ongoing timestamping.
>
> Setting based on the syscall is simpler, too. __sock_set_timestamps
> already uses for SO_TIMESTAMP(NS) the valbool approach I
> suggest for SO_TIMESTAMPING.
>
> The fallthrough can also be removed. My rough patch missed that.

Sounds good.

-Deepa
diff mbox series

Patch

diff --git a/net/core/sock.c b/net/core/sock.c
index 34a8d12e38d7..3926804702c1 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1024,16 +1024,15 @@  int sock_setsockopt(struct socket *sock, int level, int optname,
 		}
 
 		sk->sk_tsflags = val;
+		if (optname != SO_TIMESTAMPING_NEW)
+			sock_reset_flag(sk, SOCK_TSTAMP_NEW);
+
 		if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
 			sock_enable_timestamp(sk,
 					      SOCK_TIMESTAMPING_RX_SOFTWARE);
-		else {
-			if (optname == SO_TIMESTAMPING_NEW)
-				sock_reset_flag(sk, SOCK_TSTAMP_NEW);
-
+		else
 			sock_disable_timestamp(sk,
 					       (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE));
-		}
 		break;
 
 	case SO_RCVLOWAT: