summaryrefslogtreecommitdiff
path: root/components/lwp/lwp_syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp/lwp_syscall.c')
-rw-r--r--components/lwp/lwp_syscall.c225
1 files changed, 223 insertions, 2 deletions
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index 94ba29ddcd..90d116db5c 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -3535,6 +3535,150 @@ static int netflags_muslc_2_lwip(int flags)
return flgs;
}
+#ifdef ARCH_MM_MMU
+static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg,
+ struct iovec **out_iov, void **out_msg_control)
+{
+ size_t iovs_size;
+ struct iovec *uiov, *kiov;
+ size_t iovs_buffer_size = 0;
+ void *iovs_buffer;
+
+ if (!lwp_user_accessable(umsg, sizeof(*umsg)))
+ {
+ return -EFAULT;
+ }
+
+ lwp_get_from_user(kmsg, umsg, sizeof(*kmsg));
+
+ iovs_size = sizeof(*kmsg->msg_iov) * kmsg->msg_iovlen;
+ if (!lwp_user_accessable(kmsg->msg_iov, iovs_size))
+ {
+ return -EFAULT;
+ }
+
+ /* user and kernel */
+ kiov = kmem_get(iovs_size * 2);
+ if (!kiov)
+ {
+ return -ENOMEM;
+ }
+
+ uiov = (void *)kiov + iovs_size;
+ lwp_get_from_user(uiov, kmsg->msg_iov, iovs_size);
+
+ if (out_iov)
+ {
+ *out_iov = uiov;
+ }
+ kmsg->msg_iov = kiov;
+
+ for (int i = 0; i < kmsg->msg_iovlen; ++i)
+ {
+ /*
+ * We MUST check we can copy data to user after socket done in uiov
+ * otherwise we will be lost the messages from the network!
+ */
+ if (!lwp_user_accessable(uiov->iov_base, uiov->iov_len))
+ {
+ kmem_put(kmsg->msg_iov);
+
+ return -EPERM;
+ }
+
+ iovs_buffer_size += uiov->iov_len;
+ kiov->iov_len = uiov->iov_len;
+
+ ++kiov;
+ ++uiov;
+ }
+
+ /* msg_iov and msg_control */
+ iovs_buffer = kmem_get(iovs_buffer_size + kmsg->msg_controllen);
+
+ if (!iovs_buffer)
+ {
+ kmem_put(kmsg->msg_iov);
+
+ return -ENOMEM;
+ }
+
+ kiov = kmsg->msg_iov;
+
+ for (int i = 0; i < kmsg->msg_iovlen; ++i)
+ {
+ kiov->iov_base = iovs_buffer;
+ iovs_buffer += kiov->iov_len;
+ ++kiov;
+ }
+
+ *out_msg_control = kmsg->msg_control;
+ /* msg_control is the end of the iovs_buffer */
+ kmsg->msg_control = iovs_buffer;
+
+ return 0;
+}
+#endif /* ARCH_MM_MMU */
+
+sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags)
+{
+ int flgs, ret = -1;
+ struct msghdr kmsg;
+#ifdef ARCH_MM_MMU
+ void *msg_control;
+ struct iovec *uiov, *kiov;
+#endif
+
+ if (!msg)
+ {
+ return -EPERM;
+ }
+
+ flgs = netflags_muslc_2_lwip(flags);
+
+#ifdef ARCH_MM_MMU
+ ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control);
+
+ if (!ret)
+ {
+ ret = recvmsg(socket, &kmsg, flgs);
+
+ if (ret < 0)
+ {
+ goto _free_res;
+ }
+
+ kiov = kmsg.msg_iov;
+
+ for (int i = 0; i < kmsg.msg_iovlen; ++i)
+ {
+ lwp_put_to_user(uiov->iov_base, kiov->iov_base, kiov->iov_len);
+
+ ++kiov;
+ ++uiov;
+ }
+
+ lwp_put_to_user(msg_control, kmsg.msg_control, kmsg.msg_controllen);
+ lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags));
+
+ _free_res:
+ kmem_put(kmsg.msg_iov->iov_base);
+ kmem_put(kmsg.msg_iov);
+ }
+#else
+ rt_memcpy(&kmsg, msg, sizeof(kmsg));
+
+ ret = recvmsg(socket, &kmsg, flgs);
+
+ if (!ret)
+ {
+ msg->msg_flags = kmsg.msg_flags;
+ }
+#endif /* ARCH_MM_MMU */
+
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags,
struct musl_sockaddr *from, socklen_t *fromlen)
{
@@ -3633,6 +3777,57 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags)
return (ret < 0 ? GET_ERRNO() : ret);
}
+sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags)
+{
+ int flgs, ret = -1;
+ struct msghdr kmsg;
+#ifdef ARCH_MM_MMU
+ void *msg_control;
+ struct iovec *uiov, *kiov;
+#endif
+ if (!msg)
+ {
+ return -EPERM;
+ }
+
+ flgs = netflags_muslc_2_lwip(flags);
+
+#ifdef ARCH_MM_MMU
+ ret = copy_msghdr_from_user(&kmsg, (struct msghdr *)msg, &uiov, &msg_control);
+
+ if (!ret)
+ {
+ kiov = kmsg.msg_iov;
+
+ for (int i = 0; i < kmsg.msg_iovlen; ++i)
+ {
+ lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len);
+
+ ++kiov;
+ ++uiov;
+ }
+
+ lwp_get_from_user(kmsg.msg_control, msg_control, kmsg.msg_controllen);
+
+ ret = sendmsg(socket, &kmsg, flgs);
+
+ kmem_put(kmsg.msg_iov->iov_base);
+ kmem_put(kmsg.msg_iov);
+ }
+#else
+ rt_memcpy(&kmsg, msg, sizeof(kmsg));
+
+ ret = sendmsg(socket, &kmsg, flgs);
+
+ if (!ret)
+ {
+ msg->msg_flags = kmsg.msg_flags;
+ }
+#endif /* ARCH_MM_MMU */
+
+ return (ret < 0 ? GET_ERRNO() : ret);
+}
+
sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags,
const struct musl_sockaddr *to, socklen_t tolen)
{
@@ -3757,6 +3952,30 @@ out:
return (fd < 0 ? GET_ERRNO() : fd);
}
+sysret_t sys_socketpair(int domain, int type, int protocol, int fd[2])
+{
+#ifdef RT_USING_SAL
+ int ret = 0;
+ int k_fd[2];
+
+ if (!lwp_user_accessable((void *)fd, sizeof(int [2])))
+ {
+ return -EFAULT;
+ }
+
+ ret = socketpair(domain, type, protocol, k_fd);
+
+ if (ret == 0)
+ {
+ lwp_put_to_user(fd, k_fd, sizeof(int [2]));
+ }
+
+ return ret;
+#else
+ return -ELIBACC;
+#endif
+}
+
sysret_t sys_closesocket(int socket)
{
return closesocket(socket);
@@ -6688,8 +6907,8 @@ const static struct rt_syscall_def func_table[] =
SYSCALL_NET(SYSCALL_SIGN(sys_getaddrinfo)),
SYSCALL_NET(SYSCALL_SIGN(sys_gethostbyname2_r)), /* 85 */
- SYSCALL_SIGN(sys_notimpl), //network,
- SYSCALL_SIGN(sys_notimpl), //network,
+ SYSCALL_NET(SYSCALL_SIGN(sys_sendmsg)),
+ SYSCALL_NET(SYSCALL_SIGN(sys_recvmsg)),
SYSCALL_SIGN(sys_notimpl), //network,
SYSCALL_SIGN(sys_notimpl), //network,
SYSCALL_SIGN(sys_notimpl), //network, /* 90 */
@@ -6826,6 +7045,8 @@ const static struct rt_syscall_def func_table[] =
SYSCALL_SIGN(sys_ftruncate),
SYSCALL_SIGN(sys_setitimer),
SYSCALL_SIGN(sys_utimensat),
+ SYSCALL_SIGN(sys_notimpl),
+ SYSCALL_SIGN(sys_socketpair), /* 205 */
};
const void *lwp_get_sys_api(rt_uint32_t number)