xref: /linux/io_uring/cmd_net.c (revision 91db6edc573bf238c277602b2ea4b4f4688fdedc)
1*91db6edcSPavel Begunkov #include <asm/ioctls.h>
2*91db6edcSPavel Begunkov #include <linux/io_uring/net.h>
3*91db6edcSPavel Begunkov #include <net/sock.h>
4*91db6edcSPavel Begunkov 
5*91db6edcSPavel Begunkov #include "uring_cmd.h"
6*91db6edcSPavel Begunkov 
7*91db6edcSPavel Begunkov static inline int io_uring_cmd_getsockopt(struct socket *sock,
8*91db6edcSPavel Begunkov 					  struct io_uring_cmd *cmd,
9*91db6edcSPavel Begunkov 					  unsigned int issue_flags)
10*91db6edcSPavel Begunkov {
11*91db6edcSPavel Begunkov 	const struct io_uring_sqe *sqe = cmd->sqe;
12*91db6edcSPavel Begunkov 	bool compat = !!(issue_flags & IO_URING_F_COMPAT);
13*91db6edcSPavel Begunkov 	int optlen, optname, level, err;
14*91db6edcSPavel Begunkov 	void __user *optval;
15*91db6edcSPavel Begunkov 
16*91db6edcSPavel Begunkov 	level = READ_ONCE(sqe->level);
17*91db6edcSPavel Begunkov 	if (level != SOL_SOCKET)
18*91db6edcSPavel Begunkov 		return -EOPNOTSUPP;
19*91db6edcSPavel Begunkov 
20*91db6edcSPavel Begunkov 	optval = u64_to_user_ptr(READ_ONCE(sqe->optval));
21*91db6edcSPavel Begunkov 	optname = READ_ONCE(sqe->optname);
22*91db6edcSPavel Begunkov 	optlen = READ_ONCE(sqe->optlen);
23*91db6edcSPavel Begunkov 
24*91db6edcSPavel Begunkov 	err = do_sock_getsockopt(sock, compat, level, optname,
25*91db6edcSPavel Begunkov 				 USER_SOCKPTR(optval),
26*91db6edcSPavel Begunkov 				 KERNEL_SOCKPTR(&optlen));
27*91db6edcSPavel Begunkov 	if (err)
28*91db6edcSPavel Begunkov 		return err;
29*91db6edcSPavel Begunkov 
30*91db6edcSPavel Begunkov 	/* On success, return optlen */
31*91db6edcSPavel Begunkov 	return optlen;
32*91db6edcSPavel Begunkov }
33*91db6edcSPavel Begunkov 
34*91db6edcSPavel Begunkov static inline int io_uring_cmd_setsockopt(struct socket *sock,
35*91db6edcSPavel Begunkov 					  struct io_uring_cmd *cmd,
36*91db6edcSPavel Begunkov 					  unsigned int issue_flags)
37*91db6edcSPavel Begunkov {
38*91db6edcSPavel Begunkov 	const struct io_uring_sqe *sqe = cmd->sqe;
39*91db6edcSPavel Begunkov 	bool compat = !!(issue_flags & IO_URING_F_COMPAT);
40*91db6edcSPavel Begunkov 	int optname, optlen, level;
41*91db6edcSPavel Begunkov 	void __user *optval;
42*91db6edcSPavel Begunkov 	sockptr_t optval_s;
43*91db6edcSPavel Begunkov 
44*91db6edcSPavel Begunkov 	optval = u64_to_user_ptr(READ_ONCE(sqe->optval));
45*91db6edcSPavel Begunkov 	optname = READ_ONCE(sqe->optname);
46*91db6edcSPavel Begunkov 	optlen = READ_ONCE(sqe->optlen);
47*91db6edcSPavel Begunkov 	level = READ_ONCE(sqe->level);
48*91db6edcSPavel Begunkov 	optval_s = USER_SOCKPTR(optval);
49*91db6edcSPavel Begunkov 
50*91db6edcSPavel Begunkov 	return do_sock_setsockopt(sock, compat, level, optname, optval_s,
51*91db6edcSPavel Begunkov 				  optlen);
52*91db6edcSPavel Begunkov }
53*91db6edcSPavel Begunkov 
54*91db6edcSPavel Begunkov int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
55*91db6edcSPavel Begunkov {
56*91db6edcSPavel Begunkov 	struct socket *sock = cmd->file->private_data;
57*91db6edcSPavel Begunkov 	struct sock *sk = sock->sk;
58*91db6edcSPavel Begunkov 	struct proto *prot = READ_ONCE(sk->sk_prot);
59*91db6edcSPavel Begunkov 	int ret, arg = 0;
60*91db6edcSPavel Begunkov 
61*91db6edcSPavel Begunkov 	if (!prot || !prot->ioctl)
62*91db6edcSPavel Begunkov 		return -EOPNOTSUPP;
63*91db6edcSPavel Begunkov 
64*91db6edcSPavel Begunkov 	switch (cmd->cmd_op) {
65*91db6edcSPavel Begunkov 	case SOCKET_URING_OP_SIOCINQ:
66*91db6edcSPavel Begunkov 		ret = prot->ioctl(sk, SIOCINQ, &arg);
67*91db6edcSPavel Begunkov 		if (ret)
68*91db6edcSPavel Begunkov 			return ret;
69*91db6edcSPavel Begunkov 		return arg;
70*91db6edcSPavel Begunkov 	case SOCKET_URING_OP_SIOCOUTQ:
71*91db6edcSPavel Begunkov 		ret = prot->ioctl(sk, SIOCOUTQ, &arg);
72*91db6edcSPavel Begunkov 		if (ret)
73*91db6edcSPavel Begunkov 			return ret;
74*91db6edcSPavel Begunkov 		return arg;
75*91db6edcSPavel Begunkov 	case SOCKET_URING_OP_GETSOCKOPT:
76*91db6edcSPavel Begunkov 		return io_uring_cmd_getsockopt(sock, cmd, issue_flags);
77*91db6edcSPavel Begunkov 	case SOCKET_URING_OP_SETSOCKOPT:
78*91db6edcSPavel Begunkov 		return io_uring_cmd_setsockopt(sock, cmd, issue_flags);
79*91db6edcSPavel Begunkov 	default:
80*91db6edcSPavel Begunkov 		return -EOPNOTSUPP;
81*91db6edcSPavel Begunkov 	}
82*91db6edcSPavel Begunkov }
83*91db6edcSPavel Begunkov EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
84