net: rework SIOCGSTAMP ioctl handling
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. Acked-by: Stefan Schmidt <stefan@datenfreihafen.org> Acked-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Marc Kleine-Budde <mkl@pengutronix.de> Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/ Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
1ab839281c
commit
c7cbdbf29f
57
net/compat.c
57
net/compat.c
@@ -395,63 +395,6 @@ COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
|
||||
return __compat_sys_setsockopt(fd, 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(sock_read_timestamp(sk));
|
||||
|
||||
if (tv.tv_sec == -1)
|
||||
return err;
|
||||
if (tv.tv_sec == 0) {
|
||||
ktime_t kt = ktime_get_real();
|
||||
sock_write_timestamp(sk, kt);
|
||||
tv = ktime_to_timeval(kt);
|
||||
}
|
||||
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(sock_read_timestamp(sk));
|
||||
if (ts.tv_sec == -1)
|
||||
return err;
|
||||
if (ts.tv_sec == 0) {
|
||||
ktime_t kt = ktime_get_real();
|
||||
sock_write_timestamp(sk, kt);
|
||||
ts = ktime_to_timespec(kt);
|
||||
}
|
||||
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)
|
||||
|
Reference in New Issue
Block a user