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