zephyr/subsys/net/lib/sockets/sockets.c

1016 lines
24 KiB
C

/*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2021 Nordic Semiconductor
* Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Zephyr headers */
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_sock, CONFIG_NET_SOCKETS_LOG_LEVEL);
#include <zephyr/kernel.h>
#include <zephyr/tracing/tracing.h>
#include <zephyr/net/socket.h>
#include <zephyr/internal/syscall_handler.h>
#include "sockets_internal.h"
#define VTABLE_CALL(fn, sock, ...) \
({ \
const struct socket_op_vtable *vtable; \
struct k_mutex *lock; \
void *obj; \
int retval; \
\
obj = get_sock_vtable(sock, &vtable, &lock); \
if (obj == NULL) { \
errno = EBADF; \
return -1; \
} \
\
if (vtable->fn == NULL) { \
errno = EOPNOTSUPP; \
return -1; \
} \
\
(void)k_mutex_lock(lock, K_FOREVER); \
\
retval = vtable->fn(obj, __VA_ARGS__); \
\
k_mutex_unlock(lock); \
\
retval; \
})
static inline void *get_sock_vtable(int sock,
const struct socket_op_vtable **vtable,
struct k_mutex **lock)
{
void *ctx;
ctx = zvfs_get_fd_obj_and_vtable(sock,
(const struct fd_op_vtable **)vtable,
lock);
#ifdef CONFIG_USERSPACE
if (ctx != NULL && k_is_in_user_syscall()) {
if (!k_object_is_valid(ctx, K_OBJ_NET_SOCKET)) {
/* Invalidate the context, the caller doesn't have
* sufficient permission or there was some other
* problem with the net socket object
*/
ctx = NULL;
}
}
#endif /* CONFIG_USERSPACE */
if (ctx == NULL) {
NET_DBG("Invalid access on sock %d by thread %p (%s)", sock,
_current, k_thread_name_get(_current));
}
return ctx;
}
size_t msghdr_non_empty_iov_count(const struct msghdr *msg)
{
size_t non_empty_iov_count = 0;
for (size_t i = 0; i < msg->msg_iovlen; i++) {
if (msg->msg_iov[i].iov_len) {
non_empty_iov_count++;
}
}
return non_empty_iov_count;
}
void *z_impl_zsock_get_context_object(int sock)
{
const struct socket_op_vtable *ignored;
return get_sock_vtable(sock, &ignored, NULL);
}
#ifdef CONFIG_USERSPACE
void *z_vrfy_zsock_get_context_object(int sock)
{
/* All checking done in implementation */
return z_impl_zsock_get_context_object(sock);
}
#include <zephyr/syscalls/zsock_get_context_object_mrsh.c>
#endif
int z_impl_zsock_socket(int family, int type, int proto)
{
STRUCT_SECTION_FOREACH(net_socket_register, sock_family) {
int ret;
if (sock_family->family != family &&
sock_family->family != AF_UNSPEC) {
continue;
}
NET_ASSERT(sock_family->is_supported);
if (!sock_family->is_supported(family, type, proto)) {
continue;
}
errno = 0;
ret = sock_family->handler(family, type, proto);
SYS_PORT_TRACING_OBJ_INIT(socket, ret < 0 ? -errno : ret,
family, type, proto);
(void)sock_obj_core_alloc(ret, sock_family, family, type, proto);
return ret;
}
errno = EAFNOSUPPORT;
SYS_PORT_TRACING_OBJ_INIT(socket, -errno, family, type, proto);
return -1;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_socket(int family, int type, int proto)
{
/* implementation call to net_context_get() should do all necessary
* checking
*/
return z_impl_zsock_socket(family, type, proto);
}
#include <zephyr/syscalls/zsock_socket_mrsh.c>
#endif /* CONFIG_USERSPACE */
extern int zvfs_close(int fd);
int z_impl_zsock_close(int sock)
{
return zvfs_close(sock);
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_close(int sock)
{
const struct socket_op_vtable *vtable;
struct k_mutex *lock;
void *ctx;
ctx = get_sock_vtable(sock, &vtable, &lock);
if (ctx == NULL) {
errno = EBADF;
return -1;
}
return z_impl_zsock_close(sock);
}
#include <zephyr/syscalls/zsock_close_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_shutdown(int sock, int how)
{
const struct socket_op_vtable *vtable;
struct k_mutex *lock;
void *ctx;
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, shutdown, sock, how);
ctx = get_sock_vtable(sock, &vtable, &lock);
if (ctx == NULL) {
errno = EBADF;
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, -errno);
return -1;
}
if (!vtable->shutdown) {
errno = ENOTSUP;
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, -errno);
return -1;
}
(void)k_mutex_lock(lock, K_FOREVER);
NET_DBG("shutdown: ctx=%p, fd=%d, how=%d", ctx, sock, how);
ret = vtable->shutdown(ctx, how);
k_mutex_unlock(lock);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, shutdown, sock, ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_shutdown(int sock, int how)
{
return z_impl_zsock_shutdown(sock, how);
}
#include <zephyr/syscalls/zsock_shutdown_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, bind, sock, addr, addrlen);
ret = VTABLE_CALL(bind, sock, addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, bind, sock, ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_bind(int sock, const struct sockaddr *addr,
socklen_t addrlen)
{
struct sockaddr_storage dest_addr_copy;
K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy)));
K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)addr, addrlen));
return z_impl_zsock_bind(sock, (struct sockaddr *)&dest_addr_copy,
addrlen);
}
#include <zephyr/syscalls/zsock_bind_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_connect(int sock, const struct sockaddr *addr,
socklen_t addrlen)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, connect, sock, addr, addrlen);
ret = VTABLE_CALL(connect, sock, addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, connect, sock,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
int z_vrfy_zsock_connect(int sock, const struct sockaddr *addr,
socklen_t addrlen)
{
struct sockaddr_storage dest_addr_copy;
K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy)));
K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)addr, addrlen));
return z_impl_zsock_connect(sock, (struct sockaddr *)&dest_addr_copy,
addrlen);
}
#include <zephyr/syscalls/zsock_connect_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_listen(int sock, int backlog)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, listen, sock, backlog);
ret = VTABLE_CALL(listen, sock, backlog);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, listen, sock,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_listen(int sock, int backlog)
{
return z_impl_zsock_listen(sock, backlog);
}
#include <zephyr/syscalls/zsock_listen_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen)
{
int new_sock;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, accept, sock);
new_sock = VTABLE_CALL(accept, sock, addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, accept, new_sock, addr, addrlen,
new_sock < 0 ? -errno : 0);
(void)sock_obj_core_alloc_find(sock, new_sock, SOCK_STREAM);
return new_sock;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_accept(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
socklen_t addrlen_copy;
int ret;
K_OOPS(addrlen && k_usermode_from_copy(&addrlen_copy, addrlen,
sizeof(socklen_t)));
K_OOPS(addr && K_SYSCALL_MEMORY_WRITE(addr, addrlen ? addrlen_copy : 0));
ret = z_impl_zsock_accept(sock, (struct sockaddr *)addr,
addrlen ? &addrlen_copy : NULL);
K_OOPS(ret >= 0 && addrlen && k_usermode_to_copy(addrlen, &addrlen_copy,
sizeof(socklen_t)));
return ret;
}
#include <zephyr/syscalls/zsock_accept_mrsh.c>
#endif /* CONFIG_USERSPACE */
ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
int bytes_sent;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, sendto, sock, len, flags,
dest_addr, addrlen);
bytes_sent = VTABLE_CALL(sendto, sock, buf, len, flags, dest_addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, sendto, sock,
bytes_sent < 0 ? -errno : bytes_sent);
sock_obj_core_update_send_stats(sock, bytes_sent);
return bytes_sent;
}
#ifdef CONFIG_USERSPACE
ssize_t z_vrfy_zsock_sendto(int sock, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
struct sockaddr_storage dest_addr_copy;
K_OOPS(K_SYSCALL_MEMORY_READ(buf, len));
if (dest_addr) {
K_OOPS(K_SYSCALL_VERIFY(addrlen <= sizeof(dest_addr_copy)));
K_OOPS(k_usermode_from_copy(&dest_addr_copy, (void *)dest_addr,
addrlen));
}
return z_impl_zsock_sendto(sock, (const void *)buf, len, flags,
dest_addr ? (struct sockaddr *)&dest_addr_copy : NULL,
addrlen);
}
#include <zephyr/syscalls/zsock_sendto_mrsh.c>
#endif /* CONFIG_USERSPACE */
ssize_t z_impl_zsock_sendmsg(int sock, const struct msghdr *msg, int flags)
{
int bytes_sent;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, sendmsg, sock, msg, flags);
bytes_sent = VTABLE_CALL(sendmsg, sock, msg, flags);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, sendmsg, sock,
bytes_sent < 0 ? -errno : bytes_sent);
sock_obj_core_update_send_stats(sock, bytes_sent);
return bytes_sent;
}
#ifdef CONFIG_USERSPACE
static inline ssize_t z_vrfy_zsock_sendmsg(int sock,
const struct msghdr *msg,
int flags)
{
struct msghdr msg_copy;
size_t i;
int ret;
K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy)));
msg_copy.msg_name = NULL;
msg_copy.msg_control = NULL;
msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov,
msg->msg_iovlen * sizeof(struct iovec));
if (!msg_copy.msg_iov) {
errno = ENOMEM;
goto fail;
}
for (i = 0; i < msg->msg_iovlen; i++) {
msg_copy.msg_iov[i].iov_base =
k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base,
msg->msg_iov[i].iov_len);
if (!msg_copy.msg_iov[i].iov_base) {
errno = ENOMEM;
goto fail;
}
msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
}
if (msg->msg_namelen > 0) {
msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name,
msg->msg_namelen);
if (!msg_copy.msg_name) {
errno = ENOMEM;
goto fail;
}
}
if (msg->msg_controllen > 0) {
msg_copy.msg_control = k_usermode_alloc_from_copy(msg->msg_control,
msg->msg_controllen);
if (!msg_copy.msg_control) {
errno = ENOMEM;
goto fail;
}
}
ret = z_impl_zsock_sendmsg(sock, (const struct msghdr *)&msg_copy,
flags);
k_free(msg_copy.msg_name);
k_free(msg_copy.msg_control);
for (i = 0; i < msg_copy.msg_iovlen; i++) {
k_free(msg_copy.msg_iov[i].iov_base);
}
k_free(msg_copy.msg_iov);
return ret;
fail:
if (msg_copy.msg_name) {
k_free(msg_copy.msg_name);
}
if (msg_copy.msg_control) {
k_free(msg_copy.msg_control);
}
if (msg_copy.msg_iov) {
for (i = 0; i < msg_copy.msg_iovlen; i++) {
if (msg_copy.msg_iov[i].iov_base) {
k_free(msg_copy.msg_iov[i].iov_base);
}
}
k_free(msg_copy.msg_iov);
}
return -1;
}
#include <zephyr/syscalls/zsock_sendmsg_mrsh.c>
#endif /* CONFIG_USERSPACE */
ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
int bytes_received;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, recvfrom, sock, max_len, flags, src_addr, addrlen);
bytes_received = VTABLE_CALL(recvfrom, sock, buf, max_len, flags, src_addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, recvfrom, sock,
src_addr, addrlen,
bytes_received < 0 ? -errno : bytes_received);
sock_obj_core_update_recv_stats(sock, bytes_received);
return bytes_received;
}
#ifdef CONFIG_USERSPACE
ssize_t z_vrfy_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
socklen_t addrlen_copy;
ssize_t ret;
if (K_SYSCALL_MEMORY_WRITE(buf, max_len)) {
errno = EFAULT;
return -1;
}
if (addrlen) {
K_OOPS(k_usermode_from_copy(&addrlen_copy, addrlen,
sizeof(socklen_t)));
}
K_OOPS(src_addr && K_SYSCALL_MEMORY_WRITE(src_addr, addrlen_copy));
ret = z_impl_zsock_recvfrom(sock, (void *)buf, max_len, flags,
(struct sockaddr *)src_addr,
addrlen ? &addrlen_copy : NULL);
if (addrlen) {
K_OOPS(k_usermode_to_copy(addrlen, &addrlen_copy,
sizeof(socklen_t)));
}
return ret;
}
#include <zephyr/syscalls/zsock_recvfrom_mrsh.c>
#endif /* CONFIG_USERSPACE */
ssize_t z_impl_zsock_recvmsg(int sock, struct msghdr *msg, int flags)
{
int bytes_received;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, recvmsg, sock, msg, flags);
bytes_received = VTABLE_CALL(recvmsg, sock, msg, flags);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, recvmsg, sock, msg,
bytes_received < 0 ? -errno : bytes_received);
sock_obj_core_update_recv_stats(sock, bytes_received);
return bytes_received;
}
#ifdef CONFIG_USERSPACE
ssize_t z_vrfy_zsock_recvmsg(int sock, struct msghdr *msg, int flags)
{
struct msghdr msg_copy;
size_t iovlen;
size_t i;
int ret;
if (msg == NULL) {
errno = EINVAL;
return -1;
}
if (msg->msg_iov == NULL) {
errno = ENOMEM;
return -1;
}
K_OOPS(k_usermode_from_copy(&msg_copy, (void *)msg, sizeof(msg_copy)));
k_usermode_from_copy(&iovlen, &msg->msg_iovlen, sizeof(iovlen));
msg_copy.msg_name = NULL;
msg_copy.msg_control = NULL;
msg_copy.msg_iov = k_usermode_alloc_from_copy(msg->msg_iov,
msg->msg_iovlen * sizeof(struct iovec));
if (!msg_copy.msg_iov) {
errno = ENOMEM;
goto fail;
}
/* Clear the pointers in the copy so that if the allocation in the
* next loop fails, we do not try to free non allocated memory
* in fail branch.
*/
memset(msg_copy.msg_iov, 0, msg->msg_iovlen * sizeof(struct iovec));
for (i = 0; i < iovlen; i++) {
/* TODO: In practice we do not need to copy the actual data
* in msghdr when receiving data but currently there is no
* ready made function to do just that (unless we want to call
* relevant malloc function here ourselves). So just use
* the copying variant for now.
*/
msg_copy.msg_iov[i].iov_base =
k_usermode_alloc_from_copy(msg->msg_iov[i].iov_base,
msg->msg_iov[i].iov_len);
if (!msg_copy.msg_iov[i].iov_base) {
errno = ENOMEM;
goto fail;
}
msg_copy.msg_iov[i].iov_len = msg->msg_iov[i].iov_len;
}
if (msg->msg_namelen > 0) {
if (msg->msg_name == NULL) {
errno = EINVAL;
goto fail;
}
msg_copy.msg_name = k_usermode_alloc_from_copy(msg->msg_name,
msg->msg_namelen);
if (msg_copy.msg_name == NULL) {
errno = ENOMEM;
goto fail;
}
}
if (msg->msg_controllen > 0) {
if (msg->msg_control == NULL) {
errno = EINVAL;
goto fail;
}
msg_copy.msg_control =
k_usermode_alloc_from_copy(msg->msg_control,
msg->msg_controllen);
if (msg_copy.msg_control == NULL) {
errno = ENOMEM;
goto fail;
}
}
ret = z_impl_zsock_recvmsg(sock, &msg_copy, flags);
/* Do not copy anything back if there was an error or nothing was
* received.
*/
if (ret > 0) {
if (msg->msg_namelen > 0 && msg->msg_name != NULL) {
K_OOPS(k_usermode_to_copy(msg->msg_name,
msg_copy.msg_name,
msg_copy.msg_namelen));
}
if (msg->msg_controllen > 0 &&
msg->msg_control != NULL) {
K_OOPS(k_usermode_to_copy(msg->msg_control,
msg_copy.msg_control,
msg_copy.msg_controllen));
msg->msg_controllen = msg_copy.msg_controllen;
} else {
msg->msg_controllen = 0U;
}
k_usermode_to_copy(&msg->msg_iovlen,
&msg_copy.msg_iovlen,
sizeof(msg->msg_iovlen));
/* The new iovlen cannot be bigger than the original one */
NET_ASSERT(msg_copy.msg_iovlen <= iovlen);
for (i = 0; i < iovlen; i++) {
if (i < msg_copy.msg_iovlen) {
K_OOPS(k_usermode_to_copy(msg->msg_iov[i].iov_base,
msg_copy.msg_iov[i].iov_base,
msg_copy.msg_iov[i].iov_len));
K_OOPS(k_usermode_to_copy(&msg->msg_iov[i].iov_len,
&msg_copy.msg_iov[i].iov_len,
sizeof(msg->msg_iov[i].iov_len)));
} else {
/* Clear out those vectors that we could not populate */
msg->msg_iov[i].iov_len = 0;
}
}
k_usermode_to_copy(&msg->msg_flags,
&msg_copy.msg_flags,
sizeof(msg->msg_flags));
}
k_free(msg_copy.msg_name);
k_free(msg_copy.msg_control);
/* Note that we need to free according to original iovlen */
for (i = 0; i < iovlen; i++) {
k_free(msg_copy.msg_iov[i].iov_base);
}
k_free(msg_copy.msg_iov);
return ret;
fail:
if (msg_copy.msg_name) {
k_free(msg_copy.msg_name);
}
if (msg_copy.msg_control) {
k_free(msg_copy.msg_control);
}
if (msg_copy.msg_iov) {
for (i = 0; i < msg_copy.msg_iovlen; i++) {
if (msg_copy.msg_iov[i].iov_base) {
k_free(msg_copy.msg_iov[i].iov_base);
}
}
k_free(msg_copy.msg_iov);
}
return -1;
}
#include <zephyr/syscalls/zsock_recvmsg_mrsh.c>
#endif /* CONFIG_USERSPACE */
/* As this is limited function, we don't follow POSIX signature, with
* "..." instead of last arg.
*/
int z_impl_zsock_fcntl_impl(int sock, int cmd, int flags)
{
const struct socket_op_vtable *vtable;
struct k_mutex *lock;
void *obj;
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, fcntl, sock, cmd, flags);
obj = get_sock_vtable(sock, &vtable, &lock);
if (obj == NULL) {
errno = EBADF;
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, fcntl, sock, -errno);
return -1;
}
(void)k_mutex_lock(lock, K_FOREVER);
ret = zvfs_fdtable_call_ioctl((const struct fd_op_vtable *)vtable,
obj, cmd, flags);
k_mutex_unlock(lock);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, fcntl, sock,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_fcntl_impl(int sock, int cmd, int flags)
{
return z_impl_zsock_fcntl_impl(sock, cmd, flags);
}
#include <zephyr/syscalls/zsock_fcntl_impl_mrsh.c>
#endif
int z_impl_zsock_ioctl_impl(int sock, unsigned long request, va_list args)
{
const struct socket_op_vtable *vtable;
struct k_mutex *lock;
void *ctx;
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, ioctl, sock, request);
ctx = get_sock_vtable(sock, &vtable, &lock);
if (ctx == NULL) {
errno = EBADF;
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, ioctl, sock, -errno);
return -1;
}
(void)k_mutex_lock(lock, K_FOREVER);
NET_DBG("ioctl: ctx=%p, fd=%d, request=%lu", ctx, sock, request);
ret = vtable->fd_vtable.ioctl(ctx, request, args);
k_mutex_unlock(lock);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, ioctl, sock,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_ioctl_impl(int sock, unsigned long request, va_list args)
{
switch (request) {
case ZFD_IOCTL_FIONBIO:
break;
case ZFD_IOCTL_FIONREAD: {
int *avail;
avail = va_arg(args, int *);
K_OOPS(K_SYSCALL_MEMORY_WRITE(avail, sizeof(*avail)));
break;
}
default:
errno = EOPNOTSUPP;
return -1;
}
return z_impl_zsock_ioctl_impl(sock, request, args);
}
#include <zephyr/syscalls/zsock_ioctl_impl_mrsh.c>
#endif
int z_impl_zsock_inet_pton(sa_family_t family, const char *src, void *dst)
{
if (net_addr_pton(family, src, dst) == 0) {
return 1;
} else {
return 0;
}
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_inet_pton(sa_family_t family,
const char *src, void *dst)
{
int dst_size;
char src_copy[NET_IPV6_ADDR_LEN];
char dst_copy[sizeof(struct in6_addr)];
int ret;
switch (family) {
case AF_INET:
dst_size = sizeof(struct in_addr);
break;
case AF_INET6:
dst_size = sizeof(struct in6_addr);
break;
default:
errno = EAFNOSUPPORT;
return -1;
}
K_OOPS(k_usermode_string_copy(src_copy, (char *)src, sizeof(src_copy)));
ret = z_impl_zsock_inet_pton(family, src_copy, dst_copy);
K_OOPS(k_usermode_to_copy(dst, dst_copy, dst_size));
return ret;
}
#include <zephyr/syscalls/zsock_inet_pton_mrsh.c>
#endif
int z_impl_zsock_getsockopt(int sock, int level, int optname,
void *optval, socklen_t *optlen)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getsockopt, sock, level, optname);
ret = VTABLE_CALL(getsockopt, sock, level, optname, optval, optlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getsockopt, sock, level, optname,
optval, *optlen, ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
int z_vrfy_zsock_getsockopt(int sock, int level, int optname,
void *optval, socklen_t *optlen)
{
socklen_t kernel_optlen = *(socklen_t *)optlen;
void *kernel_optval;
int ret;
if (K_SYSCALL_MEMORY_WRITE(optval, kernel_optlen)) {
errno = -EPERM;
return -1;
}
kernel_optval = k_usermode_alloc_from_copy((const void *)optval,
kernel_optlen);
K_OOPS(!kernel_optval);
ret = z_impl_zsock_getsockopt(sock, level, optname,
kernel_optval, &kernel_optlen);
K_OOPS(k_usermode_to_copy((void *)optval, kernel_optval, kernel_optlen));
K_OOPS(k_usermode_to_copy((void *)optlen, &kernel_optlen,
sizeof(socklen_t)));
k_free(kernel_optval);
return ret;
}
#include <zephyr/syscalls/zsock_getsockopt_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_setsockopt(int sock, int level, int optname,
const void *optval, socklen_t optlen)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, setsockopt, sock,
level, optname, optval, optlen);
ret = VTABLE_CALL(setsockopt, sock, level, optname, optval, optlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, setsockopt, sock,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
int z_vrfy_zsock_setsockopt(int sock, int level, int optname,
const void *optval, socklen_t optlen)
{
void *kernel_optval;
int ret;
kernel_optval = k_usermode_alloc_from_copy((const void *)optval, optlen);
K_OOPS(!kernel_optval);
ret = z_impl_zsock_setsockopt(sock, level, optname,
kernel_optval, optlen);
k_free(kernel_optval);
return ret;
}
#include <zephyr/syscalls/zsock_setsockopt_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_getpeername(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getpeername, sock);
ret = VTABLE_CALL(getpeername, sock, addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getpeername, sock,
addr, addrlen,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_getpeername(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
socklen_t addrlen_copy;
int ret;
K_OOPS(k_usermode_from_copy(&addrlen_copy, (void *)addrlen,
sizeof(socklen_t)));
if (K_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) {
errno = EFAULT;
return -1;
}
ret = z_impl_zsock_getpeername(sock, (struct sockaddr *)addr,
&addrlen_copy);
if (ret == 0 &&
k_usermode_to_copy((void *)addrlen, &addrlen_copy,
sizeof(socklen_t))) {
errno = EINVAL;
return -1;
}
return ret;
}
#include <zephyr/syscalls/zsock_getpeername_mrsh.c>
#endif /* CONFIG_USERSPACE */
int z_impl_zsock_getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
int ret;
SYS_PORT_TRACING_OBJ_FUNC_ENTER(socket, getsockname, sock);
ret = VTABLE_CALL(getsockname, sock, addr, addrlen);
SYS_PORT_TRACING_OBJ_FUNC_EXIT(socket, getsockname, sock,
addr, addrlen,
ret < 0 ? -errno : ret);
return ret;
}
#ifdef CONFIG_USERSPACE
static inline int z_vrfy_zsock_getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
socklen_t addrlen_copy;
int ret;
K_OOPS(k_usermode_from_copy(&addrlen_copy, (void *)addrlen,
sizeof(socklen_t)));
if (K_SYSCALL_MEMORY_WRITE(addr, addrlen_copy)) {
errno = EFAULT;
return -1;
}
ret = z_impl_zsock_getsockname(sock, (struct sockaddr *)addr,
&addrlen_copy);
if (ret == 0 &&
k_usermode_to_copy((void *)addrlen, &addrlen_copy,
sizeof(socklen_t))) {
errno = EINVAL;
return -1;
}
return ret;
}
#include <zephyr/syscalls/zsock_getsockname_mrsh.c>
#endif /* CONFIG_USERSPACE */