1 // SPDX-License-Identifier: GPL-2.0
2 #include <asm/ioctls.h>
3 #include <linux/io_uring/net.h>
4 #include <linux/errqueue.h>
5 #include <net/sock.h>
6
7 #include "uring_cmd.h"
8 #include "io_uring.h"
9
io_uring_cmd_getsockopt(struct socket * sock,struct io_uring_cmd * cmd,unsigned int issue_flags)10 static inline int io_uring_cmd_getsockopt(struct socket *sock,
11 struct io_uring_cmd *cmd,
12 unsigned int issue_flags)
13 {
14 const struct io_uring_sqe *sqe = cmd->sqe;
15 bool compat = !!(issue_flags & IO_URING_F_COMPAT);
16 int optlen, optname, level, err;
17 void __user *optval;
18
19 level = READ_ONCE(sqe->level);
20 if (level != SOL_SOCKET)
21 return -EOPNOTSUPP;
22
23 optval = u64_to_user_ptr(READ_ONCE(sqe->optval));
24 optname = READ_ONCE(sqe->optname);
25 optlen = READ_ONCE(sqe->optlen);
26
27 err = do_sock_getsockopt(sock, compat, level, optname,
28 USER_SOCKPTR(optval),
29 KERNEL_SOCKPTR(&optlen));
30 if (err)
31 return err;
32
33 /* On success, return optlen */
34 return optlen;
35 }
36
io_uring_cmd_setsockopt(struct socket * sock,struct io_uring_cmd * cmd,unsigned int issue_flags)37 static inline int io_uring_cmd_setsockopt(struct socket *sock,
38 struct io_uring_cmd *cmd,
39 unsigned int issue_flags)
40 {
41 const struct io_uring_sqe *sqe = cmd->sqe;
42 bool compat = !!(issue_flags & IO_URING_F_COMPAT);
43 int optname, optlen, level;
44 void __user *optval;
45 sockptr_t optval_s;
46
47 optval = u64_to_user_ptr(READ_ONCE(sqe->optval));
48 optname = READ_ONCE(sqe->optname);
49 optlen = READ_ONCE(sqe->optlen);
50 level = READ_ONCE(sqe->level);
51 optval_s = USER_SOCKPTR(optval);
52
53 return do_sock_setsockopt(sock, compat, level, optname, optval_s,
54 optlen);
55 }
56
io_process_timestamp_skb(struct io_uring_cmd * cmd,struct sock * sk,struct sk_buff * skb,unsigned issue_flags)57 static bool io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk,
58 struct sk_buff *skb, unsigned issue_flags)
59 {
60 struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
61 struct io_uring_cqe cqe[2];
62 struct io_timespec *iots;
63 struct timespec64 ts;
64 u32 tstype, tskey;
65 int ret;
66
67 BUILD_BUG_ON(sizeof(struct io_uring_cqe) != sizeof(struct io_timespec));
68
69 ret = skb_get_tx_timestamp(skb, sk, &ts);
70 if (ret < 0)
71 return false;
72
73 tskey = serr->ee.ee_data;
74 tstype = serr->ee.ee_info;
75
76 cqe->user_data = 0;
77 cqe->res = tskey;
78 cqe->flags = IORING_CQE_F_MORE | ctx_cqe32_flags(cmd_to_io_kiocb(cmd)->ctx);
79 cqe->flags |= tstype << IORING_TIMESTAMP_TYPE_SHIFT;
80 if (ret == SOF_TIMESTAMPING_TX_HARDWARE)
81 cqe->flags |= IORING_CQE_F_TSTAMP_HW;
82
83 iots = (struct io_timespec *)&cqe[1];
84 iots->tv_sec = ts.tv_sec;
85 iots->tv_nsec = ts.tv_nsec;
86 return io_uring_cmd_post_mshot_cqe32(cmd, issue_flags, cqe);
87 }
88
io_uring_cmd_timestamp(struct socket * sock,struct io_uring_cmd * cmd,unsigned int issue_flags)89 static int io_uring_cmd_timestamp(struct socket *sock,
90 struct io_uring_cmd *cmd,
91 unsigned int issue_flags)
92 {
93 struct sock *sk = sock->sk;
94 struct sk_buff_head *q = &sk->sk_error_queue;
95 struct sk_buff *skb, *tmp;
96 struct sk_buff_head list;
97 int ret;
98
99 if (!(issue_flags & IO_URING_F_CQE32))
100 return -EINVAL;
101 ret = io_cmd_poll_multishot(cmd, issue_flags, EPOLLERR);
102 if (unlikely(ret))
103 return ret;
104
105 if (skb_queue_empty_lockless(q))
106 return -EAGAIN;
107 __skb_queue_head_init(&list);
108
109 scoped_guard(spinlock_irq, &q->lock) {
110 skb_queue_walk_safe(q, skb, tmp) {
111 /* don't support skbs with payload */
112 if (!skb_has_tx_timestamp(skb, sk) || skb->len)
113 continue;
114 __skb_unlink(skb, q);
115 __skb_queue_tail(&list, skb);
116 }
117 }
118
119 while (1) {
120 skb = skb_peek(&list);
121 if (!skb)
122 break;
123 if (!io_process_timestamp_skb(cmd, sk, skb, issue_flags))
124 break;
125 __skb_dequeue(&list);
126 consume_skb(skb);
127 }
128
129 if (!unlikely(skb_queue_empty(&list))) {
130 scoped_guard(spinlock_irqsave, &q->lock)
131 skb_queue_splice(&list, q);
132 }
133 return -EAGAIN;
134 }
135
io_uring_cmd_getsockname(struct socket * sock,struct io_uring_cmd * cmd,unsigned int issue_flags)136 static int io_uring_cmd_getsockname(struct socket *sock,
137 struct io_uring_cmd *cmd,
138 unsigned int issue_flags)
139 {
140 const struct io_uring_sqe *sqe = cmd->sqe;
141 struct sockaddr __user *uaddr;
142 unsigned int peer;
143 int __user *ulen;
144
145 if (sqe->ioprio || sqe->__pad1 || sqe->len || sqe->rw_flags)
146 return -EINVAL;
147
148 uaddr = u64_to_user_ptr(READ_ONCE(sqe->addr));
149 ulen = u64_to_user_ptr(READ_ONCE(sqe->addr3));
150 peer = READ_ONCE(sqe->optlen);
151 if (peer > 1)
152 return -EINVAL;
153 return do_getsockname(sock, peer, uaddr, ulen);
154 }
155
io_uring_cmd_sock(struct io_uring_cmd * cmd,unsigned int issue_flags)156 int io_uring_cmd_sock(struct io_uring_cmd *cmd, unsigned int issue_flags)
157 {
158 struct socket *sock = cmd->file->private_data;
159 struct sock *sk = sock->sk;
160 struct proto *prot = READ_ONCE(sk->sk_prot);
161 int ret, arg = 0;
162
163 switch (cmd->cmd_op) {
164 case SOCKET_URING_OP_SIOCINQ:
165 if (!prot || !prot->ioctl)
166 return -EOPNOTSUPP;
167
168 ret = prot->ioctl(sk, SIOCINQ, &arg);
169 if (ret)
170 return ret;
171 return arg;
172 case SOCKET_URING_OP_SIOCOUTQ:
173 if (!prot || !prot->ioctl)
174 return -EOPNOTSUPP;
175
176 ret = prot->ioctl(sk, SIOCOUTQ, &arg);
177 if (ret)
178 return ret;
179 return arg;
180 case SOCKET_URING_OP_GETSOCKOPT:
181 return io_uring_cmd_getsockopt(sock, cmd, issue_flags);
182 case SOCKET_URING_OP_SETSOCKOPT:
183 return io_uring_cmd_setsockopt(sock, cmd, issue_flags);
184 case SOCKET_URING_OP_TX_TIMESTAMP:
185 return io_uring_cmd_timestamp(sock, cmd, issue_flags);
186 case SOCKET_URING_OP_GETSOCKNAME:
187 return io_uring_cmd_getsockname(sock, cmd, issue_flags);
188 default:
189 return -EOPNOTSUPP;
190 }
191 }
192 EXPORT_SYMBOL_GPL(io_uring_cmd_sock);
193