The SIOCGSTAMP/SIOCGSTAMPNS ioctl commands are implemented by many
socket protocol handlers, and all of those end up calling the same
sock_get_timestamp()/sock_get_timestampns() helper functions, which
results in a lot of duplicate code.

With the introduction of 64-bit time_t on 32-bit architectures, this
gets worse, as we then need four different ioctl commands in each
socket protocol implementation.

To simplify that, let's add a new .gettstamp() operation in
struct proto_ops, and move ioctl implementation into the common
sock_ioctl()/compat_sock_ioctl_trans() functions that these all go
through.

We can reuse the sock_get_timestamp() implementation, but generalize
it so it can deal with both native and compat mode, as well as
timeval and timespec structures.

Signed-off-by: Arnd Bergmann <a...@arndb.de>
---
 include/linux/net.h          |  2 ++
 include/net/compat.h         |  3 --
 include/net/sock.h           |  4 +--
 net/appletalk/ddp.c          |  7 +----
 net/atm/ioctl.c              | 16 -----------
 net/atm/pvc.c                |  1 +
 net/atm/svc.c                |  1 +
 net/ax25/af_ax25.c           |  9 +-----
 net/bluetooth/af_bluetooth.c |  8 ------
 net/bluetooth/l2cap_sock.c   |  1 +
 net/bluetooth/rfcomm/sock.c  |  1 +
 net/bluetooth/sco.c          |  1 +
 net/can/af_can.c             |  6 ----
 net/can/bcm.c                |  1 +
 net/can/raw.c                |  1 +
 net/compat.c                 | 54 ------------------------------------
 net/core/sock.c              | 38 +++++++++++--------------
 net/dccp/ipv4.c              |  1 +
 net/dccp/ipv6.c              |  1 +
 net/ieee802154/socket.c      |  6 ++--
 net/ipv4/af_inet.c           |  9 ++----
 net/ipv6/af_inet6.c          |  8 ++----
 net/ipv6/raw.c               |  1 +
 net/l2tp/l2tp_ip.c           |  1 +
 net/l2tp/l2tp_ip6.c          |  1 +
 net/netrom/af_netrom.c       | 14 +---------
 net/packet/af_packet.c       |  7 ++---
 net/qrtr/qrtr.c              |  4 +--
 net/rose/af_rose.c           |  7 +----
 net/sctp/ipv6.c              |  1 +
 net/sctp/protocol.c          |  1 +
 net/socket.c                 | 48 ++++++++++----------------------
 net/x25/af_x25.c             | 27 +-----------------
 33 files changed, 63 insertions(+), 228 deletions(-)

diff --git a/include/linux/net.h b/include/linux/net.h
index e0930678c8bf..2be3e9c772fe 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -155,6 +155,8 @@ struct proto_ops {
        int             (*compat_ioctl) (struct socket *sock, unsigned int cmd,
                                      unsigned long arg);
 #endif
+       int             (*gettstamp) (struct socket *sock, void __user 
*userstamp,
+                                     bool timeval, bool time32);
        int             (*listen)    (struct socket *sock, int len);
        int             (*shutdown)  (struct socket *sock, int flags);
        int             (*setsockopt)(struct socket *sock, int level,
diff --git a/include/net/compat.h b/include/net/compat.h
index 4c6d75612b6c..f277653c7e17 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -30,9 +30,6 @@ struct compat_cmsghdr {
        compat_int_t    cmsg_type;
 };
 
-int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
-int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
-
 #else /* defined(CONFIG_COMPAT) */
 /*
  * To avoid compiler warnings:
diff --git a/include/net/sock.h b/include/net/sock.h
index 433f45fc2d68..ef6c9409dc75 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1584,6 +1584,8 @@ int sock_setsockopt(struct socket *sock, int level, int 
op,
 
 int sock_getsockopt(struct socket *sock, int level, int op,
                    char __user *optval, int __user *optlen);
+int sock_gettstamp(struct socket *sock, void __user *userstamp,
+                  bool timeval, bool time32);
 struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
                                    int noblock, int *errcode);
 struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
@@ -2423,8 +2425,6 @@ static inline bool sk_listener(const struct sock *sk)
 }
 
 void sock_enable_timestamp(struct sock *sk, int flag);
-int sock_get_timestamp(struct sock *, struct timeval __user *);
-int sock_get_timestampns(struct sock *, struct timespec __user *);
 int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level,
                       int type);
 
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 9b6bc5abe946..a21a643997aa 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1806,12 +1806,6 @@ static int atalk_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
                rc = put_user(amount, (int __user *)argp);
                break;
        }
-       case SIOCGSTAMP:
-               rc = sock_get_timestamp(sk, argp);
-               break;
-       case SIOCGSTAMPNS:
-               rc = sock_get_timestampns(sk, argp);
-               break;
        /* Routing */
        case SIOCADDRT:
        case SIOCDELRT:
@@ -1871,6 +1865,7 @@ static const struct proto_ops atalk_dgram_ops = {
        .getname        = atalk_getname,
        .poll           = datagram_poll,
        .ioctl          = atalk_ioctl,
+       .gettstamp      = sock_gettstamp,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = atalk_compat_ioctl,
 #endif
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 2ff0e5e470e3..d955b683aa7c 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -81,22 +81,6 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int 
cmd,
                                 (int __user *)argp) ? -EFAULT : 0;
                goto done;
        }
-       case SIOCGSTAMP: /* borrowed from IP */
-#ifdef CONFIG_COMPAT
-               if (compat)
-                       error = compat_sock_get_timestamp(sk, argp);
-               else
-#endif
-                       error = sock_get_timestamp(sk, argp);
-               goto done;
-       case SIOCGSTAMPNS: /* borrowed from IP */
-#ifdef CONFIG_COMPAT
-               if (compat)
-                       error = compat_sock_get_timestampns(sk, argp);
-               else
-#endif
-                       error = sock_get_timestampns(sk, argp);
-               goto done;
        case ATM_SETSC:
                net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n",
                                     current->comm, task_pid_nr(current));
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index 2cb10af16afc..02bd2a436bdf 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -118,6 +118,7 @@ static const struct proto_ops pvc_proto_ops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl = vcc_compat_ioctl,
 #endif
+       .gettstamp =    sock_gettstamp,
        .listen =       sock_no_listen,
        .shutdown =     pvc_shutdown,
        .setsockopt =   pvc_setsockopt,
diff --git a/net/atm/svc.c b/net/atm/svc.c
index 2f91b766ac42..908cbb8654f5 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -641,6 +641,7 @@ static const struct proto_ops svc_proto_ops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl = svc_compat_ioctl,
 #endif
+       .gettstamp =    sock_gettstamp,
        .listen =       svc_listen,
        .shutdown =     svc_shutdown,
        .setsockopt =   svc_setsockopt,
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index c603d33d5410..121f7b877df9 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1707,14 +1707,6 @@ static int ax25_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
                break;
        }
 
-       case SIOCGSTAMP:
-               res = sock_get_timestamp(sk, argp);
-               break;
-
-       case SIOCGSTAMPNS:
-               res = sock_get_timestampns(sk, argp);
-               break;
-
        case SIOCAX25ADDUID:    /* Add a uid to the uid/call map table */
        case SIOCAX25DELUID:    /* Delete a uid from the uid/call map table */
        case SIOCAX25GETUID: {
@@ -1943,6 +1935,7 @@ static const struct proto_ops ax25_proto_ops = {
        .getname        = ax25_getname,
        .poll           = datagram_poll,
        .ioctl          = ax25_ioctl,
+       .gettstamp      = sock_gettstamp,
        .listen         = ax25_listen,
        .shutdown       = ax25_shutdown,
        .setsockopt     = ax25_setsockopt,
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index deacc52d7ff1..34e15ca66779 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -511,14 +511,6 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, 
unsigned long arg)
                err = put_user(amount, (int __user *) arg);
                break;
 
-       case SIOCGSTAMP:
-               err = sock_get_timestamp(sk, (struct timeval __user *) arg);
-               break;
-
-       case SIOCGSTAMPNS:
-               err = sock_get_timestampns(sk, (struct timespec __user *) arg);
-               break;
-
        default:
                err = -ENOIOCTLCMD;
                break;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 686bdc6b35b0..e8fed07a49d5 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1655,6 +1655,7 @@ static const struct proto_ops l2cap_sock_ops = {
        .recvmsg        = l2cap_sock_recvmsg,
        .poll           = bt_sock_poll,
        .ioctl          = bt_sock_ioctl,
+       .gettstamp      = sock_gettstamp,
        .mmap           = sock_no_mmap,
        .socketpair     = sock_no_socketpair,
        .shutdown       = l2cap_sock_shutdown,
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index d606e9212291..a1dde6fab323 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -1049,6 +1049,7 @@ static const struct proto_ops rfcomm_sock_ops = {
        .setsockopt     = rfcomm_sock_setsockopt,
        .getsockopt     = rfcomm_sock_getsockopt,
        .ioctl          = rfcomm_sock_ioctl,
+       .gettstamp      = sock_gettstamp,
        .poll           = bt_sock_poll,
        .socketpair     = sock_no_socketpair,
        .mmap           = sock_no_mmap
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 8f0f9279eac9..e7e5b3ed0394 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1200,6 +1200,7 @@ static const struct proto_ops sco_sock_ops = {
        .recvmsg        = sco_sock_recvmsg,
        .poll           = bt_sock_poll,
        .ioctl          = bt_sock_ioctl,
+       .gettstamp      = sock_gettstamp,
        .mmap           = sock_no_mmap,
        .socketpair     = sock_no_socketpair,
        .shutdown       = sco_sock_shutdown,
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 1684ba5b51eb..e8fd5dc1780a 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -89,13 +89,7 @@ static atomic_t skbcounter = ATOMIC_INIT(0);
 
 int can_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-       struct sock *sk = sock->sk;
-
        switch (cmd) {
-
-       case SIOCGSTAMP:
-               return sock_get_timestamp(sk, (struct timeval __user *)arg);
-
        default:
                return -ENOIOCTLCMD;
        }
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 0af8f0db892a..db3e521b9f47 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1662,6 +1662,7 @@ static const struct proto_ops bcm_ops = {
        .getname       = sock_no_getname,
        .poll          = datagram_poll,
        .ioctl         = can_ioctl,     /* use can_ioctl() from af_can.c */
+       .gettstamp     = sock_gettstamp,
        .listen        = sock_no_listen,
        .shutdown      = sock_no_shutdown,
        .setsockopt    = sock_no_setsockopt,
diff --git a/net/can/raw.c b/net/can/raw.c
index 1051eee82581..968f6f8082a1 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -845,6 +845,7 @@ static const struct proto_ops raw_ops = {
        .getname       = raw_getname,
        .poll          = datagram_poll,
        .ioctl         = can_ioctl,     /* use can_ioctl() from af_can.c */
+       .gettstamp     = sock_gettstamp,
        .listen        = sock_no_listen,
        .shutdown      = sock_no_shutdown,
        .setsockopt    = raw_setsockopt,
diff --git a/net/compat.c b/net/compat.c
index 47a614b370cd..e5456dd4c7a5 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -455,60 +455,6 @@ static int compat_sock_getsockopt(struct socket *sock, int 
level, int optname,
        return sock_getsockopt(sock, level, optname, optval, optlen);
 }
 
-int compat_sock_get_timestamp(struct sock *sk, struct timeval __user 
*userstamp)
-{
-       struct compat_timeval __user *ctv;
-       int err;
-       struct timeval tv;
-
-       if (COMPAT_USE_64BIT_TIME)
-               return sock_get_timestamp(sk, userstamp);
-
-       ctv = (struct compat_timeval __user *) userstamp;
-       err = -ENOENT;
-       sock_enable_timestamp(sk, SOCK_TIMESTAMP);
-       tv = ktime_to_timeval(sk->sk_stamp);
-       if (tv.tv_sec == -1)
-               return err;
-       if (tv.tv_sec == 0) {
-               sk->sk_stamp = ktime_get_real();
-               tv = ktime_to_timeval(sk->sk_stamp);
-       }
-       err = 0;
-       if (put_user(tv.tv_sec, &ctv->tv_sec) ||
-                       put_user(tv.tv_usec, &ctv->tv_usec))
-               err = -EFAULT;
-       return err;
-}
-EXPORT_SYMBOL(compat_sock_get_timestamp);
-
-int compat_sock_get_timestampns(struct sock *sk, struct timespec __user 
*userstamp)
-{
-       struct compat_timespec __user *ctv;
-       int err;
-       struct timespec ts;
-
-       if (COMPAT_USE_64BIT_TIME)
-               return sock_get_timestampns (sk, userstamp);
-
-       ctv = (struct compat_timespec __user *) userstamp;
-       err = -ENOENT;
-       sock_enable_timestamp(sk, SOCK_TIMESTAMP);
-       ts = ktime_to_timespec(sk->sk_stamp);
-       if (ts.tv_sec == -1)
-               return err;
-       if (ts.tv_sec == 0) {
-               sk->sk_stamp = ktime_get_real();
-               ts = ktime_to_timespec(sk->sk_stamp);
-       }
-       err = 0;
-       if (put_user(ts.tv_sec, &ctv->tv_sec) ||
-                       put_user(ts.tv_nsec, &ctv->tv_nsec))
-               err = -EFAULT;
-       return err;
-}
-EXPORT_SYMBOL(compat_sock_get_timestampns);
-
 static int __compat_sys_getsockopt(int fd, int level, int optname,
                                   char __user *optval,
                                   int __user *optlen)
diff --git a/net/core/sock.c b/net/core/sock.c
index 3730eb855095..df17bbfaca27 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2897,37 +2897,31 @@ bool lock_sock_fast(struct sock *sk)
 }
 EXPORT_SYMBOL(lock_sock_fast);
 
-int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
+int sock_gettstamp(struct socket *sock, void __user *userstamp,
+                  bool timeval, bool time32)
 {
-       struct timeval tv;
-
-       sock_enable_timestamp(sk, SOCK_TIMESTAMP);
-       tv = ktime_to_timeval(sk->sk_stamp);
-       if (tv.tv_sec == -1)
-               return -ENOENT;
-       if (tv.tv_sec == 0) {
-               sk->sk_stamp = ktime_get_real();
-               tv = ktime_to_timeval(sk->sk_stamp);
-       }
-       return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0;
-}
-EXPORT_SYMBOL(sock_get_timestamp);
-
-int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
-{
-       struct timespec ts;
+       struct sock *sk = sock->sk;
+       struct timespec64 ts;
 
        sock_enable_timestamp(sk, SOCK_TIMESTAMP);
-       ts = ktime_to_timespec(sk->sk_stamp);
+       ts = ktime_to_timespec64(sk->sk_stamp);
        if (ts.tv_sec == -1)
                return -ENOENT;
        if (ts.tv_sec == 0) {
                sk->sk_stamp = ktime_get_real();
-               ts = ktime_to_timespec(sk->sk_stamp);
+               ts = ktime_to_timespec64(sk->sk_stamp);
        }
-       return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
+
+       if (timeval)
+               ts.tv_nsec /= 1000;
+#ifdef CONFIG_COMPAT_32BIT_TIME
+       if (time32)
+               return put_old_timespec32(&ts, userstamp);
+#endif
+
+       return put_timespec64(&ts, userstamp);
 }
-EXPORT_SYMBOL(sock_get_timestampns);
+EXPORT_SYMBOL(sock_gettstamp);
 
 void sock_enable_timestamp(struct sock *sk, int flag)
 {
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index b08feb219b44..8103f3525773 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -986,6 +986,7 @@ static const struct proto_ops inet_dccp_ops = {
        /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
        .poll              = dccp_poll,
        .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
        /* FIXME: work on inet_listen to rename it to sock_common_listen */
        .listen            = inet_dccp_listen,
        .shutdown          = inet_shutdown,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 6344f1b18a6a..dacdb5b2638d 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -1072,6 +1072,7 @@ static const struct proto_ops inet6_dccp_ops = {
        .getname           = inet6_getname,
        .poll              = dccp_poll,
        .ioctl             = inet6_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = inet_dccp_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index bc6b912603f1..ce2dfb997537 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -164,10 +164,6 @@ static int ieee802154_sock_ioctl(struct socket *sock, 
unsigned int cmd,
        struct sock *sk = sock->sk;
 
        switch (cmd) {
-       case SIOCGSTAMP:
-               return sock_get_timestamp(sk, (struct timeval __user *)arg);
-       case SIOCGSTAMPNS:
-               return sock_get_timestampns(sk, (struct timespec __user *)arg);
        case SIOCGIFADDR:
        case SIOCSIFADDR:
                return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
@@ -426,6 +422,7 @@ static const struct proto_ops ieee802154_raw_ops = {
        .getname           = sock_no_getname,
        .poll              = datagram_poll,
        .ioctl             = ieee802154_sock_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,
        .shutdown          = sock_no_shutdown,
        .setsockopt        = sock_common_setsockopt,
@@ -988,6 +985,7 @@ static const struct proto_ops ieee802154_dgram_ops = {
        .getname           = sock_no_getname,
        .poll              = datagram_poll,
        .ioctl             = ieee802154_sock_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,
        .shutdown          = sock_no_shutdown,
        .setsockopt        = sock_common_setsockopt,
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 20fda8fb8ffd..3490275bab50 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -911,12 +911,6 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, 
unsigned long arg)
        struct rtentry rt;
 
        switch (cmd) {
-       case SIOCGSTAMP:
-               err = sock_get_timestamp(sk, (struct timeval __user *)arg);
-               break;
-       case SIOCGSTAMPNS:
-               err = sock_get_timestampns(sk, (struct timespec __user *)arg);
-               break;
        case SIOCADDRT:
        case SIOCDELRT:
                if (copy_from_user(&rt, p, sizeof(struct rtentry)))
@@ -988,6 +982,7 @@ const struct proto_ops inet_stream_ops = {
        .getname           = inet_getname,
        .poll              = tcp_poll,
        .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = inet_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
@@ -1023,6 +1018,7 @@ const struct proto_ops inet_dgram_ops = {
        .getname           = inet_getname,
        .poll              = udp_poll,
        .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
@@ -1055,6 +1051,7 @@ static const struct proto_ops inet_sockraw_ops = {
        .getname           = inet_getname,
        .poll              = datagram_poll,
        .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 673bba31eb18..77f9716958a7 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -532,12 +532,6 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, 
unsigned long arg)
        struct net *net = sock_net(sk);
 
        switch (cmd) {
-       case SIOCGSTAMP:
-               return sock_get_timestamp(sk, (struct timeval __user *)arg);
-
-       case SIOCGSTAMPNS:
-               return sock_get_timestampns(sk, (struct timespec __user *)arg);
-
        case SIOCADDRT:
        case SIOCDELRT:
 
@@ -570,6 +564,7 @@ const struct proto_ops inet6_stream_ops = {
        .getname           = inet6_getname,
        .poll              = tcp_poll,                  /* ok           */
        .ioctl             = inet6_ioctl,               /* must change  */
+       .gettstamp         = sock_gettstamp,
        .listen            = inet_listen,               /* ok           */
        .shutdown          = inet_shutdown,             /* ok           */
        .setsockopt        = sock_common_setsockopt,    /* ok           */
@@ -603,6 +598,7 @@ const struct proto_ops inet6_dgram_ops = {
        .getname           = inet6_getname,
        .poll              = udp_poll,                  /* ok           */
        .ioctl             = inet6_ioctl,               /* must change  */
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,            /* ok           */
        .shutdown          = inet_shutdown,             /* ok           */
        .setsockopt        = sock_common_setsockopt,    /* ok           */
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 413d98bf24f4..a913ccfff021 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1344,6 +1344,7 @@ const struct proto_ops inet6_sockraw_ops = {
        .getname           = inet6_getname,
        .poll              = datagram_poll,             /* ok           */
        .ioctl             = inet6_ioctl,               /* must change  */
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,            /* ok           */
        .shutdown          = inet_shutdown,             /* ok           */
        .setsockopt        = sock_common_setsockopt,    /* ok           */
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index 35f6f86d4dcc..b7b844d9edec 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -615,6 +615,7 @@ static const struct proto_ops l2tp_ip_ops = {
        .getname           = l2tp_ip_getname,
        .poll              = datagram_poll,
        .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 237f1a4a0b0c..c379ebfa4cb7 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -751,6 +751,7 @@ static const struct proto_ops l2tp_ip6_ops = {
        .getname           = l2tp_ip6_getname,
        .poll              = datagram_poll,
        .ioctl             = inet6_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sock_no_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 03f37c4e64fe..687103e0a3c8 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1194,7 +1194,6 @@ static int nr_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
 {
        struct sock *sk = sock->sk;
        void __user *argp = (void __user *)arg;
-       int ret;
 
        switch (cmd) {
        case TIOCOUTQ: {
@@ -1220,18 +1219,6 @@ static int nr_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
                return put_user(amount, (int __user *)argp);
        }
 
-       case SIOCGSTAMP:
-               lock_sock(sk);
-               ret = sock_get_timestamp(sk, argp);
-               release_sock(sk);
-               return ret;
-
-       case SIOCGSTAMPNS:
-               lock_sock(sk);
-               ret = sock_get_timestampns(sk, argp);
-               release_sock(sk);
-               return ret;
-
        case SIOCGIFADDR:
        case SIOCSIFADDR:
        case SIOCGIFDSTADDR:
@@ -1357,6 +1344,7 @@ static const struct proto_ops nr_proto_ops = {
        .getname        =       nr_getname,
        .poll           =       datagram_poll,
        .ioctl          =       nr_ioctl,
+       .gettstamp      =       sock_gettstamp,
        .listen         =       nr_listen,
        .shutdown       =       sock_no_shutdown,
        .setsockopt     =       nr_setsockopt,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 5610061e7f2e..06097f1e060b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4053,11 +4053,6 @@ static int packet_ioctl(struct socket *sock, unsigned 
int cmd,
                spin_unlock_bh(&sk->sk_receive_queue.lock);
                return put_user(amount, (int __user *)arg);
        }
-       case SIOCGSTAMP:
-               return sock_get_timestamp(sk, (struct timeval __user *)arg);
-       case SIOCGSTAMPNS:
-               return sock_get_timestampns(sk, (struct timespec __user *)arg);
-
 #ifdef CONFIG_INET
        case SIOCADDRT:
        case SIOCDELRT:
@@ -4415,6 +4410,7 @@ static const struct proto_ops packet_ops_spkt = {
        .getname =      packet_getname_spkt,
        .poll =         datagram_poll,
        .ioctl =        packet_ioctl,
+       .gettstamp =    sock_gettstamp,
        .listen =       sock_no_listen,
        .shutdown =     sock_no_shutdown,
        .setsockopt =   sock_no_setsockopt,
@@ -4436,6 +4432,7 @@ static const struct proto_ops packet_ops = {
        .getname =      packet_getname,
        .poll =         packet_poll,
        .ioctl =        packet_ioctl,
+       .gettstamp =    sock_gettstamp,
        .listen =       sock_no_listen,
        .shutdown =     sock_no_shutdown,
        .setsockopt =   packet_setsockopt,
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index 86e1e37eb4e8..9da159f3fc2a 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -967,9 +967,6 @@ static int qrtr_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
                        break;
                }
                break;
-       case SIOCGSTAMP:
-               rc = sock_get_timestamp(sk, argp);
-               break;
        case SIOCADDRT:
        case SIOCDELRT:
        case SIOCSIFADDR:
@@ -1032,6 +1029,7 @@ static const struct proto_ops qrtr_proto_ops = {
        .recvmsg        = qrtr_recvmsg,
        .getname        = qrtr_getname,
        .ioctl          = qrtr_ioctl,
+       .gettstamp      = sock_gettstamp,
        .poll           = datagram_poll,
        .shutdown       = sock_no_shutdown,
        .setsockopt     = sock_no_setsockopt,
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index d00a0ef39a56..64bcbb22c8f7 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1299,12 +1299,6 @@ static int rose_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
                return put_user(amount, (unsigned int __user *) argp);
        }
 
-       case SIOCGSTAMP:
-               return sock_get_timestamp(sk, (struct timeval __user *) argp);
-
-       case SIOCGSTAMPNS:
-               return sock_get_timestampns(sk, (struct timespec __user *) 
argp);
-
        case SIOCGIFADDR:
        case SIOCSIFADDR:
        case SIOCGIFDSTADDR:
@@ -1472,6 +1466,7 @@ static const struct proto_ops rose_proto_ops = {
        .getname        =       rose_getname,
        .poll           =       datagram_poll,
        .ioctl          =       rose_ioctl,
+       .gettstamp      =       sock_gettstamp,
        .listen         =       rose_listen,
        .shutdown       =       sock_no_shutdown,
        .setsockopt     =       rose_setsockopt,
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index fc6c5e4bffa5..62da13b888e0 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -1028,6 +1028,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
        .getname           = sctp_getname,
        .poll              = sctp_poll,
        .ioctl             = inet6_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sctp_inet_listen,
        .shutdown          = inet_shutdown,
        .setsockopt        = sock_common_setsockopt,
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index e948db29ab53..b640eeedc8b4 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1026,6 +1026,7 @@ static const struct proto_ops inet_seqpacket_ops = {
        .getname           = inet_getname,      /* Semantics are different.  */
        .poll              = sctp_poll,
        .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
        .listen            = sctp_inet_listen,
        .shutdown          = inet_shutdown,     /* Looks harmless.  */
        .setsockopt        = sock_common_setsockopt, /* IP_SOL IP_OPTION is a 
problem */
diff --git a/net/socket.c b/net/socket.c
index b9d71b503720..6814e8dc8af1 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1069,6 +1069,15 @@ static long sock_ioctl(struct file *file, unsigned cmd, 
unsigned long arg)
 
                        err = open_related_ns(&net->ns, get_net_ns);
                        break;
+               case SIOCGSTAMP:
+               case SIOCGSTAMPNS:
+                       if (!sock->ops->gettstamp) {
+                               err = -ENOIOCTLCMD;
+                               break;
+                       }
+                       err = sock->ops->gettstamp(sock, argp,
+                                                  cmd == SIOCGSTAMP, false);
+                       break;
                default:
                        err = sock_do_ioctl(net, sock, cmd, arg);
                        break;
@@ -2740,38 +2749,6 @@ void socket_seq_show(struct seq_file *seq)
 #endif                         /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_COMPAT
-static int do_siocgstamp(struct net *net, struct socket *sock,
-                        unsigned int cmd, void __user *up)
-{
-       mm_segment_t old_fs = get_fs();
-       struct timeval ktv;
-       int err;
-
-       set_fs(KERNEL_DS);
-       err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
-       set_fs(old_fs);
-       if (!err)
-               err = compat_put_timeval(&ktv, up);
-
-       return err;
-}
-
-static int do_siocgstampns(struct net *net, struct socket *sock,
-                          unsigned int cmd, void __user *up)
-{
-       mm_segment_t old_fs = get_fs();
-       struct timespec kts;
-       int err;
-
-       set_fs(KERNEL_DS);
-       err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
-       set_fs(old_fs);
-       if (!err)
-               err = compat_put_timespec(&kts, up);
-
-       return err;
-}
-
 static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user 
*uifc32)
 {
        struct compat_ifconf ifc32;
@@ -3119,9 +3096,12 @@ static int compat_sock_ioctl_trans(struct file *file, 
struct socket *sock,
        case SIOCDELRT:
                return routing_ioctl(net, sock, cmd, argp);
        case SIOCGSTAMP:
-               return do_siocgstamp(net, sock, cmd, argp);
        case SIOCGSTAMPNS:
-               return do_siocgstampns(net, sock, cmd, argp);
+               if (!sock->ops->gettstamp)
+                       return -ENOIOCTLCMD;
+               return sock->ops->gettstamp(sock, argp, cmd == SIOCGSTAMP,
+                                           !COMPAT_USE_64BIT_TIME);
+
        case SIOCBONDSLAVEINFOQUERY:
        case SIOCBONDINFOQUERY:
        case SIOCSHWTSTAMP:
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index d49aa79b7997..fe2673d17009 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1388,18 +1388,6 @@ static int x25_ioctl(struct socket *sock, unsigned int 
cmd, unsigned long arg)
                break;
        }
 
-       case SIOCGSTAMP:
-               rc = -EINVAL;
-               if (sk)
-                       rc = sock_get_timestamp(sk,
-                                               (struct timeval __user *)argp);
-               break;
-       case SIOCGSTAMPNS:
-               rc = -EINVAL;
-               if (sk)
-                       rc = sock_get_timestampns(sk,
-                                       (struct timespec __user *)argp);
-               break;
        case SIOCGIFADDR:
        case SIOCSIFADDR:
        case SIOCGIFDSTADDR:
@@ -1671,8 +1659,6 @@ static int compat_x25_ioctl(struct socket *sock, unsigned 
int cmd,
                                unsigned long arg)
 {
        void __user *argp = compat_ptr(arg);
-       struct sock *sk = sock->sk;
-
        int rc = -ENOIOCTLCMD;
 
        switch(cmd) {
@@ -1680,18 +1666,6 @@ static int compat_x25_ioctl(struct socket *sock, 
unsigned int cmd,
        case TIOCINQ:
                rc = x25_ioctl(sock, cmd, (unsigned long)argp);
                break;
-       case SIOCGSTAMP:
-               rc = -EINVAL;
-               if (sk)
-                       rc = compat_sock_get_timestamp(sk,
-                                       (struct timeval __user*)argp);
-               break;
-       case SIOCGSTAMPNS:
-               rc = -EINVAL;
-               if (sk)
-                       rc = compat_sock_get_timestampns(sk,
-                                       (struct timespec __user*)argp);
-               break;
        case SIOCGIFADDR:
        case SIOCSIFADDR:
        case SIOCGIFDSTADDR:
@@ -1755,6 +1729,7 @@ static const struct proto_ops x25_proto_ops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl = compat_x25_ioctl,
 #endif
+       .gettstamp =    sock_gettstamp,
        .listen =       x25_listen,
        .shutdown =     sock_no_shutdown,
        .setsockopt =   x25_setsockopt,
-- 
2.18.0

Reply via email to