Skip to content

Commit

Permalink
net: rework SIOCGSTAMP ioctl handling
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Neil Horman <[email protected]>
Acked-by: Marc Kleine-Budde <[email protected]>
Link: https://lore.kernel.org/lkml/CAK8P3a038aDQQotzua_QtKGhq8O9n+rdiz2=WDCp82ys8eUT+A@mail.gmail.com/
Signed-off-by: Arnd Bergmann <[email protected]>
Acked-by: Willem de Bruijn <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
arndb authored and davem330 committed Apr 19, 2019
1 parent 1ab8392 commit c7cbdbf
Show file tree
Hide file tree
Showing 33 changed files with 75 additions and 232 deletions.
2 changes: 2 additions & 0 deletions include/linux/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,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,
Expand Down
3 changes: 0 additions & 3 deletions include/net/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,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,
Expand Down Expand Up @@ -2503,8 +2505,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);

Expand Down
7 changes: 1 addition & 6 deletions net/appletalk/ddp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
16 changes: 0 additions & 16 deletions net/atm/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions net/atm/pvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions net/atm/svc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 1 addition & 8 deletions net/ax25/af_ax25.c
Original file line number Diff line number Diff line change
Expand Up @@ -1714,14 +1714,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: {
Expand Down Expand Up @@ -1950,6 +1942,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,
Expand Down
8 changes: 0 additions & 8 deletions net/bluetooth/af_bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,14 +521,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;
Expand Down
1 change: 1 addition & 0 deletions net/bluetooth/l2cap_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions net/bluetooth/rfcomm/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,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
Expand Down
1 change: 1 addition & 0 deletions net/bluetooth/sco.c
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,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,
Expand Down
6 changes: 0 additions & 6 deletions net/can/af_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions net/can/bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,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,
Expand Down
1 change: 1 addition & 0 deletions net/can/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,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,
Expand Down
57 changes: 0 additions & 57 deletions net/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
51 changes: 28 additions & 23 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -2977,39 +2977,44 @@ 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;
struct sock *sk = sock->sk;
struct timespec64 ts;

sock_enable_timestamp(sk, SOCK_TIMESTAMP);
tv = ktime_to_timeval(sock_read_timestamp(sk));
if (tv.tv_sec == -1)
ts = ktime_to_timespec64(sock_read_timestamp(sk));
if (ts.tv_sec == -1)
return -ENOENT;
if (tv.tv_sec == 0) {
if (ts.tv_sec == 0) {
ktime_t kt = ktime_get_real();
sock_write_timestamp(sk, kt);
tv = ktime_to_timeval(kt);
sock_write_timestamp(sk, kt);;
ts = ktime_to_timespec64(kt);
}
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;
if (timeval)
ts.tv_nsec /= 1000;

sock_enable_timestamp(sk, SOCK_TIMESTAMP);
ts = ktime_to_timespec(sock_read_timestamp(sk));
if (ts.tv_sec == -1)
return -ENOENT;
if (ts.tv_sec == 0) {
ktime_t kt = ktime_get_real();
sock_write_timestamp(sk, kt);
ts = ktime_to_timespec(sk->sk_stamp);
#ifdef CONFIG_COMPAT_32BIT_TIME
if (time32)
return put_old_timespec32(&ts, userstamp);
#endif
#ifdef CONFIG_SPARC64
/* beware of padding in sparc64 timeval */
if (timeval && !in_compat_syscall()) {
struct __kernel_old_timeval __user tv = {
.tv_sec = ts.tv_sec;
.tv_usec = ts.tv_nsec;
};
if (copy_to_user(userstamp, &tv, sizeof(tv))
return -EFAULT;
return 0;
}
return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
#endif
return put_timespec64(&ts, userstamp);
}
EXPORT_SYMBOL(sock_get_timestampns);
EXPORT_SYMBOL(sock_gettstamp);

void sock_enable_timestamp(struct sock *sk, int flag)
{
Expand Down
1 change: 1 addition & 0 deletions net/dccp/ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,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,
Expand Down
1 change: 1 addition & 0 deletions net/dccp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,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,
Expand Down
6 changes: 2 additions & 4 deletions net/ieee802154/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit c7cbdbf

Please sign in to comment.