cmd_net.c 4.9 KB

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