| #include <asm/ioctls.h> |
| #include <linux/io_uring/net.h> |
| #include <net/sock.h> |
| |
| #include "uring_cmd.h" |
| |
| static inline int io_uring_cmd_getsockopt(struct socket *sock, |
| struct io_uring_cmd *cmd, |
| unsigned int issue_flags) |
| { |
| const struct io_uring_sqe *sqe = cmd->sqe; |
| bool compat = !!(issue_flags & IO_URING_F_COMPAT); |
| int optlen, optname, level, err; |
| void __user *optval; |
| |
| level = READ_ONCE(sqe->level); |
| if (level != SOL_SOCKET) |
| return -EOPNOTSUPP; |
| |
| optval = u64_to_user_ptr(READ_ONCE(sqe->optval)); |
| optname = READ_ONCE(sqe->optname); |
| optlen = READ_ONCE(sqe->optlen); |
| |
| err = do_sock_getsockopt(sock, compat, level, optname, |
| USER_SOCKPTR(optval), |
| KERNEL_SOCKPTR(&optlen)); |
| if (err) |
| return err; |
| |
| /* On success, return optlen */ |
| return optlen; |
| } |
| |
| static inline int io_uring_cmd_setsockopt(struct socket *sock, |
| struct io_uring_cmd *cmd, |
| unsigned int issue_flags) |
| { |
| const struct io_uring_sqe *sqe = cmd->sqe; |
| bool compat = !!(issue_flags & IO_URING_F_COMPAT); |
| int optname, optlen, level; |
| void __user *optval; |
| sockptr_t optval_s; |
| |
| optval = u64_to_user_ptr(READ_ONCE(sqe->optval)); |
| optname = READ_ONCE(sqe->optname); |
| optlen = READ_ONCE(sqe->optlen); |
| level = READ_ONCE(sqe->level); |
| optval_s = USER_SOCKPTR(optval); |
| |
| return do_sock_setsockopt(sock, compat, level, optname, optval_s, |
| optlen); |
| } |
| |
| int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags) |
| { |
| struct socket *sock = cmd->file->private_data; |
| struct sock *sk = sock->sk; |
| struct proto *prot = READ_ONCE(sk->sk_prot); |
| int ret, arg = 0; |
| |
| if (!prot || !prot->ioctl) |
| return -EOPNOTSUPP; |
| |
| switch (cmd->cmd_op) { |
| case SOCKET_URING_OP_SIOCINQ: |
| ret = prot->ioctl(sk, SIOCINQ, &arg); |
| if (ret) |
| return ret; |
| return arg; |
| case SOCKET_URING_OP_SIOCOUTQ: |
| ret = prot->ioctl(sk, SIOCOUTQ, &arg); |
| if (ret) |
| return ret; |
| return arg; |
| case SOCKET_URING_OP_GETSOCKOPT: |
| return io_uring_cmd_getsockopt(sock, cmd, issue_flags); |
| case SOCKET_URING_OP_SETSOCKOPT: |
| return io_uring_cmd_setsockopt(sock, cmd, issue_flags); |
| default: |
| return -EOPNOTSUPP; |
| } |
| } |
| EXPORT_SYMBOL_GPL(io_uring_cmd_sock); |