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