diff options
Diffstat (limited to 'components/lwp/lwp_syscall.c')
| -rw-r--r-- | components/lwp/lwp_syscall.c | 225 |
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) |
