diff --git a/include/posix/sys/ioctl.h b/include/posix/sys/ioctl.h index 35e046ab8d26b..e69ab670fb84e 100644 --- a/include/posix/sys/ioctl.h +++ b/include/posix/sys/ioctl.h @@ -6,6 +6,15 @@ #ifndef ZEPHYR_INCLUDE_POSIX_SYS_IOCTL_H_ #define ZEPHYR_INCLUDE_POSIX_SYS_IOCTL_H_ +#include + +__syscall int sys_ioctl(int fd, unsigned long request, long n_args, uintptr_t *args); +int ioctl(int fd, unsigned long request, ...); + #define FIONBIO 0x5421 +#ifndef CONFIG_ARCH_POSIX +#include +#endif /* CONFIG_ARCH_POSIX */ + #endif /* ZEPHYR_INCLUDE_POSIX_SYS_IOCTL_H_ */ diff --git a/include/posix/unistd.h b/include/posix/unistd.h index e9c955c5bf0d1..3765ad4381ae3 100644 --- a/include/posix/unistd.h +++ b/include/posix/unistd.h @@ -22,7 +22,15 @@ extern "C" { #endif #ifdef CONFIG_POSIX_API -/* File related operations */ +/* File related operations. Convention: "sys_name" is a syscall (needs + * prototype in this file for usage). "name" is a normal userspace + * function (implemented as a wrapper for syscall), usable even + * without prototype, per classical C handling. This distinction + * is however implemented on demand, based on the actual usecases seen. + */ +__syscall int sys_close(int file); +__syscall ssize_t sys_write(int file, const void *buffer, size_t count); +__syscall ssize_t sys_read(int file, void *buffer, size_t count); extern int close(int file); extern ssize_t write(int file, const void *buffer, size_t count); extern ssize_t read(int file, void *buffer, size_t count); @@ -50,4 +58,8 @@ int usleep(useconds_t useconds); } #endif +#ifndef CONFIG_ARCH_POSIX +#include +#endif /* CONFIG_ARCH_POSIX */ + #endif /* ZEPHYR_INCLUDE_POSIX_UNISTD_H_ */ diff --git a/include/sys/fdtable.h b/include/sys/fdtable.h index 0cd4b2513d032..4485609590de7 100644 --- a/include/sys/fdtable.h +++ b/include/sys/fdtable.h @@ -22,7 +22,8 @@ extern "C" { struct fd_op_vtable { ssize_t (*read)(void *obj, void *buf, size_t sz); ssize_t (*write)(void *obj, const void *buf, size_t sz); - int (*ioctl)(void *obj, unsigned int request, va_list args); + int (*ioctl)(void *obj, unsigned long request, + long n_args, uintptr_t *args); }; /** @@ -113,14 +114,20 @@ void *z_get_fd_obj_and_vtable(int fd, const struct fd_op_vtable **vtable); * @param ... Variadic arguments to ioctl */ static inline int z_fdtable_call_ioctl(const struct fd_op_vtable *vtable, void *obj, - unsigned long request, ...) + unsigned long request, int n_args, ...) { - va_list args; - int res; + va_list varargs; + int i, res; + uintptr_t args[3]; - va_start(args, request); - res = vtable->ioctl(obj, request, args); - va_end(args); + __ASSERT_NO_MSG(n_args <= ARRAY_SIZE(args)); + + va_start(varargs, n_args); + for (i = 0; i < n_args; i++) { + args[i] = va_arg(varargs, uintptr_t); + } + res = vtable->ioctl(obj, request, n_args, args); + va_end(varargs); return res; } @@ -138,10 +145,15 @@ enum { ZFD_IOCTL_CLOSE = 0x100, ZFD_IOCTL_FSYNC, ZFD_IOCTL_LSEEK, - ZFD_IOCTL_POLL_PREPARE, + ZFD_IOCTL_GETSOCKNAME, + + /* Codes above 0xff00 are private kernel-only requests, not + * available from userspace. + */ + ZFD_IOCTL_PRIVATE = 0xff00, + ZFD_IOCTL_POLL_PREPARE = ZFD_IOCTL_PRIVATE, ZFD_IOCTL_POLL_UPDATE, ZFD_IOCTL_POLL_OFFLOAD, - ZFD_IOCTL_GETSOCKNAME, }; #ifdef __cplusplus diff --git a/lib/os/fdtable.c b/lib/os/fdtable.c index 53dcbecf15379..e08e75cbeeb14 100644 --- a/lib/os/fdtable.c +++ b/lib/os/fdtable.c @@ -18,8 +18,21 @@ #include #include #include +#ifdef CONFIG_POSIX_API +#include +#include +#endif #include +/* Number of arguments which can be passed to public ioctl calls + * (i.e. from userspace to kernel space). + * Arbitrary value is supported (at the expense of stack usage). Can + * be increased when ioctl's with more arguments are added. + * Note that kernelspace-kernelspace ioctl calls are handled + * differently (in z_fdtable_call_ioctl()). + */ +#define MAX_USERSPACE_IOCTL_ARGS 1 + struct fd_entry { void *obj; const struct fd_op_vtable *vtable; @@ -167,7 +180,7 @@ int z_alloc_fd(void *obj, const struct fd_op_vtable *vtable) #ifdef CONFIG_POSIX_API -ssize_t read(int fd, void *buf, size_t sz) +ssize_t z_impl_sys_read(int fd, void *buf, size_t sz) { if (_check_fd(fd) < 0) { return -1; @@ -175,9 +188,30 @@ ssize_t read(int fd, void *buf, size_t sz) return fdtable[fd].vtable->read(fdtable[fd].obj, buf, sz); } + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_sys_read(int fd, void *buf, size_t sz) +{ + if (Z_SYSCALL_MEMORY_WRITE(buf, sz)) { + errno = EFAULT; + return -1; + } + + return z_impl_sys_read(fd, buf, sz); +} +#include +#endif /* CONFIG_USERSPACE */ + +/* Normal C function wrapping a corresponding syscall. Required to ensure + * classic C linkage. + */ +ssize_t read(int fd, void *buf, size_t sz) +{ + return sys_read(fd, buf, sz); +} FUNC_ALIAS(read, _read, ssize_t); -ssize_t write(int fd, const void *buf, size_t sz) +ssize_t z_impl_sys_write(int fd, const void *buf, size_t sz) { if (_check_fd(fd) < 0) { return -1; @@ -185,9 +219,27 @@ ssize_t write(int fd, const void *buf, size_t sz) return fdtable[fd].vtable->write(fdtable[fd].obj, buf, sz); } + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_sys_write(int fd, const void *buf, size_t sz) +{ + Z_OOPS(Z_SYSCALL_MEMORY_READ(buf, sz)); + + return z_impl_sys_write(fd, buf, sz); +} +#include +#endif /* CONFIG_USERSPACE */ + +/* Normal C function wrapping a corresponding syscall. Required to ensure + * classic C linkage. + */ +ssize_t write(int fd, const void *buf, size_t sz) +{ + return sys_write(fd, buf, sz); +} FUNC_ALIAS(write, _write, ssize_t); -int close(int fd) +int z_impl_sys_close(int fd) { int res; @@ -195,11 +247,24 @@ int close(int fd) return -1; } - res = z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_CLOSE); + res = z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_CLOSE, 0); z_free_fd(fd); return res; } + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_sys_close(int fd) +{ + return z_impl_sys_close(fd); +} +#include +#endif /* CONFIG_USERSPACE */ + +int close(int fd) +{ + return sys_close(fd); +} FUNC_ALIAS(close, _close, int); int fsync(int fd) @@ -208,7 +273,8 @@ int fsync(int fd) return -1; } - return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_FSYNC); + return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, + ZFD_IOCTL_FSYNC, 0); } off_t lseek(int fd, off_t offset, int whence) @@ -217,22 +283,78 @@ off_t lseek(int fd, off_t offset, int whence) return -1; } - return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_LSEEK, - offset, whence); + return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, + ZFD_IOCTL_LSEEK, + 2, offset, whence); } FUNC_ALIAS(lseek, _lseek, off_t); -int ioctl(int fd, unsigned long request, ...) +int z_impl_sys_ioctl(int fd, unsigned long request, long n_args, uintptr_t *args) { - va_list args; - int res; - if (_check_fd(fd) < 0) { return -1; } + return fdtable[fd].vtable->ioctl(fdtable[fd].obj, request, n_args, args); +} + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_sys_ioctl(int fd, unsigned long request, long n_args, uintptr_t *args) +{ + Z_OOPS(Z_SYSCALL_MEMORY_READ(args, sizeof(*args) * n_args)); + + if (request >= ZFD_IOCTL_PRIVATE) { + errno = EINVAL; + return -1; + } + + return z_impl_sys_ioctl(fd, request, n_args, args); +} +#include +#endif /* CONFIG_USERSPACE */ + +static int _vioctl(int fd, unsigned long request, va_list args) +{ + int i, n_args; + /* We assume that for argument passing [on stack], natural word size + * of the plaform is used. So for example, for LP64 platform, where + * int is 32-bit, it's still pushed as 64-bit value on stack. + */ + uintptr_t marshalled_args[MAX_USERSPACE_IOCTL_ARGS]; + + /* Calculate number of arguments for individual ioctl requests. */ + switch (request) { + case F_GETFL: + n_args = 0; + break; + case F_SETFL: + n_args = 1; + break; + default: + errno = EINVAL; + return -1; + } + + if (n_args > ARRAY_SIZE(marshalled_args)) { + /* Use distinguishable error code. */ + errno = EDOM; + return -1; + } + + for (i = 0; i < n_args; i++) { + marshalled_args[i] = va_arg(args, uintptr_t); + } + + return sys_ioctl(fd, request, n_args, marshalled_args); +} + +int ioctl(int fd, unsigned long request, ...) +{ + va_list args; + int res; + va_start(args, request); - res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, request, args); + res = _vioctl(fd, request, args); va_end(args); return res; @@ -249,10 +371,6 @@ int fcntl(int fd, int cmd, ...) va_list args; int res; - if (_check_fd(fd) < 0) { - return -1; - } - /* Handle fdtable commands. */ switch (cmd) { case F_DUPFD: @@ -263,7 +381,7 @@ int fcntl(int fd, int cmd, ...) /* The rest of commands are per-fd, handled by ioctl vmethod. */ va_start(args, cmd); - res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, cmd, args); + res = _vioctl(fd, cmd, args); va_end(args); return res; @@ -292,7 +410,8 @@ static ssize_t stdinout_write_vmeth(void *obj, const void *buffer, size_t count) #endif } -static int stdinout_ioctl_vmeth(void *obj, unsigned int request, va_list args) +static int stdinout_ioctl_vmeth(void *obj, unsigned long request, + long n_args, uintptr_t *args) { errno = EINVAL; return -1; diff --git a/lib/posix/eventfd.c b/lib/posix/eventfd.c index 27d9c9487d577..1ddd26b57ac92 100644 --- a/lib/posix/eventfd.c +++ b/lib/posix/eventfd.c @@ -133,7 +133,8 @@ static ssize_t eventfd_write_op(void *obj, const void *buf, size_t sz) return sizeof(eventfd_t); } -static int eventfd_ioctl_op(void *obj, unsigned int request, va_list args) +static int eventfd_ioctl_op(void *obj, unsigned long request, + long n_args, uintptr_t *args) { struct eventfd *efd = (struct eventfd *)obj; @@ -144,7 +145,7 @@ static int eventfd_ioctl_op(void *obj, unsigned int request, va_list args) case F_SETFL: { int flags; - flags = va_arg(args, int); + flags = (int)args[0]; if (flags & ~EFD_FLAGS_SET) { errno = EINVAL; @@ -165,9 +166,9 @@ static int eventfd_ioctl_op(void *obj, unsigned int request, va_list args) struct k_poll_event **pev; struct k_poll_event *pev_end; - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); - pev_end = va_arg(args, struct k_poll_event *); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; + pev_end = (struct k_poll_event *)args[2]; return eventfd_poll_prepare(obj, pfd, pev, pev_end); } @@ -176,8 +177,8 @@ static int eventfd_ioctl_op(void *obj, unsigned int request, va_list args) struct zsock_pollfd *pfd; struct k_poll_event **pev; - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; return eventfd_poll_update(obj, pfd, pev); } diff --git a/lib/posix/fs.c b/lib/posix/fs.c index ba1ed9a9f7814..e81be5a8bf503 100644 --- a/lib/posix/fs.c +++ b/lib/posix/fs.c @@ -93,7 +93,8 @@ int open(const char *name, int flags) return fd; } -static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args) +static int fs_ioctl_vmeth(void *obj, unsigned long request, + long n_args, uintptr_t *args) { int rc; struct posix_fs_desc *ptr = obj; @@ -108,8 +109,8 @@ static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args) off_t offset; int whence; - offset = va_arg(args, off_t); - whence = va_arg(args, int); + offset = (off_t)args[0]; + whence = (int)args[1]; rc = fs_seek(&ptr->file, offset, whence); break; diff --git a/subsys/net/lib/sockets/socketpair.c b/subsys/net/lib/sockets/socketpair.c index fb5be1e69be53..7e1abea42a7c2 100644 --- a/subsys/net/lib/sockets/socketpair.c +++ b/subsys/net/lib/sockets/socketpair.c @@ -879,7 +879,8 @@ static int zsock_poll_update_ctx(struct spair *const spair, return res; } -static int spair_ioctl(void *obj, unsigned int request, va_list args) +static int spair_ioctl(void *obj, unsigned long request, + long n_args, uintptr_t *args) { int res; struct zsock_pollfd *pfd; @@ -915,7 +916,7 @@ static int spair_ioctl(void *obj, unsigned int request, va_list args) } case F_SETFL: { - flags = va_arg(args, int); + flags = (int)args[0]; if (flags & O_NONBLOCK) { spair->flags |= SPAIR_FLAG_NONBLOCK; @@ -936,17 +937,17 @@ static int spair_ioctl(void *obj, unsigned int request, va_list args) } case ZFD_IOCTL_POLL_PREPARE: { - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); - pev_end = va_arg(args, struct k_poll_event *); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; + pev_end = (struct k_poll_event *)args[2]; res = zsock_poll_prepare_ctx(obj, pfd, pev, pev_end); goto out; } case ZFD_IOCTL_POLL_UPDATE: { - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; res = zsock_poll_update_ctx(obj, pfd, pev); goto out; diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 0baaf11d21ebf..0453bea2f27db 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -258,7 +258,7 @@ int z_impl_zsock_close(int sock) NET_DBG("close: ctx=%p, fd=%d", ctx, sock); return z_fdtable_call_ioctl((const struct fd_op_vtable *)vtable, - ctx, ZFD_IOCTL_CLOSE); + ctx, ZFD_IOCTL_CLOSE, 0); } #ifdef CONFIG_USERSPACE @@ -1095,7 +1095,7 @@ int z_impl_zsock_fcntl(int sock, int cmd, int flags) } return z_fdtable_call_ioctl((const struct fd_op_vtable *)vtable, - obj, cmd, flags); + obj, cmd, 1, flags); } #ifdef CONFIG_USERSPACE @@ -1206,7 +1206,7 @@ int z_impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int poll_timeout) result = z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_PREPARE, - pfd, &pev, pev_end); + 3, pfd, &pev, pev_end); if (result == -EALREADY) { /* If POLL_PREPARE returned with EALREADY, it means * it already detected that some socket is ready. In @@ -1224,7 +1224,7 @@ int z_impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int poll_timeout) */ return z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_OFFLOAD, - fds, nfds, poll_timeout); + 3, fds, nfds, poll_timeout); } else if (result != 0) { errno = -result; return -1; @@ -1274,7 +1274,7 @@ int z_impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int poll_timeout) result = z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_UPDATE, - pfd, &pev); + 2, pfd, &pev); if (result == -EAGAIN) { retry = true; continue; @@ -1633,7 +1633,7 @@ int z_impl_zsock_getsockname(int sock, struct sockaddr *addr, NET_DBG("getsockname: ctx=%p, fd=%d", ctx, sock); return z_fdtable_call_ioctl((const struct fd_op_vtable *)vtable, ctx, - ZFD_IOCTL_GETSOCKNAME, addr, addrlen); + ZFD_IOCTL_GETSOCKNAME, 2, addr, addrlen); } #ifdef CONFIG_USERSPACE @@ -1676,7 +1676,7 @@ static ssize_t sock_write_vmeth(void *obj, const void *buffer, size_t count) return zsock_sendto_ctx(obj, buffer, count, 0, NULL, 0); } -static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) +static int sock_ioctl_vmeth(void *obj, unsigned long request, long n_args, uintptr_t *args) { switch (request) { @@ -1691,7 +1691,7 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) case F_SETFL: { int flags; - flags = va_arg(args, int); + flags = (int)args[0]; if (flags & O_NONBLOCK) { sock_set_flag(obj, SOCK_NONBLOCK, SOCK_NONBLOCK); @@ -1710,9 +1710,9 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) struct k_poll_event **pev; struct k_poll_event *pev_end; - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); - pev_end = va_arg(args, struct k_poll_event *); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; + pev_end = (struct k_poll_event *)args[2]; return zsock_poll_prepare_ctx(obj, pfd, pev, pev_end); } @@ -1721,8 +1721,8 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) struct zsock_pollfd *pfd; struct k_poll_event **pev; - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; return zsock_poll_update_ctx(obj, pfd, pev); } @@ -1731,8 +1731,8 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) struct sockaddr *addr; socklen_t *addrlen; - addr = va_arg(args, struct sockaddr *); - addrlen = va_arg(args, socklen_t *); + addr = (struct sockaddr *)args[0]; + addrlen = (socklen_t *)args[1]; return zsock_getsockname_ctx(obj, addr, addrlen); } diff --git a/subsys/net/lib/sockets/sockets_can.c b/subsys/net/lib/sockets/sockets_can.c index e549bd73eb45a..58778ee6f41d9 100644 --- a/subsys/net/lib/sockets/sockets_can.c +++ b/subsys/net/lib/sockets/sockets_can.c @@ -407,7 +407,8 @@ static int can_close_socket(struct net_context *ctx) return 0; } -static int can_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) +static int can_sock_ioctl_vmeth(void *obj, unsigned long request, + long n_args, uintptr_t *args) { if (request == ZFD_IOCTL_CLOSE) { int ret; @@ -418,7 +419,7 @@ static int can_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) } } - return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args); + return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, n_args, args); } /* diff --git a/subsys/net/lib/sockets/sockets_net_mgmt.c b/subsys/net/lib/sockets/sockets_net_mgmt.c index 7f0fa646876f1..8f6c9ba8ab05c 100644 --- a/subsys/net/lib/sockets/sockets_net_mgmt.c +++ b/subsys/net/lib/sockets/sockets_net_mgmt.c @@ -302,8 +302,8 @@ static ssize_t net_mgmt_sock_write(void *obj, const void *buffer, return znet_mgmt_sendto(obj, buffer, count, 0, NULL, 0); } -static int net_mgmt_sock_ioctl(void *obj, unsigned int request, - va_list args) +static int net_mgmt_sock_ioctl(void *obj, unsigned long request, + long n_args, uintptr_t *args) { return 0; } diff --git a/subsys/net/lib/sockets/sockets_packet.c b/subsys/net/lib/sockets/sockets_packet.c index 41fafd40d6a8c..d91cf7d6050fa 100644 --- a/subsys/net/lib/sockets/sockets_packet.c +++ b/subsys/net/lib/sockets/sockets_packet.c @@ -280,10 +280,10 @@ static ssize_t packet_sock_write_vmeth(void *obj, const void *buffer, return zpacket_sendto_ctx(obj, buffer, count, 0, NULL, 0); } -static int packet_sock_ioctl_vmeth(void *obj, unsigned int request, - va_list args) +static int packet_sock_ioctl_vmeth(void *obj, unsigned long request, + long n_args, uintptr_t *args) { - return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args); + return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, n_args, args); } /* diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index a477317bd9c08..ec0a3640a54a3 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -1197,7 +1197,7 @@ int ztls_close_ctx(struct net_context *ctx) err = -EBADF; } - ret = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, ctx, ZFD_IOCTL_CLOSE); + ret = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, ctx, ZFD_IOCTL_CLOSE, 0); /* In case close fails, we propagate errno value set by close. * In case close succeeds, but tls_release fails, set errno @@ -1331,7 +1331,7 @@ int ztls_accept_ctx(struct net_context *parent, struct sockaddr *addr, __ASSERT(err == 0, "TLS context release failed"); } - err = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, child, ZFD_IOCTL_CLOSE); + err = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, child, ZFD_IOCTL_CLOSE, 0); __ASSERT(err == 0, "Child socket close failed"); z_free_fd(fd); @@ -1936,7 +1936,8 @@ static ssize_t tls_sock_write_vmeth(void *obj, const void *buffer, return ztls_sendto_ctx(obj, buffer, count, 0, NULL, 0); } -static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) +static int tls_sock_ioctl_vmeth(void *obj, unsigned long request, + long n_args, uintptr_t *args) { switch (request) { @@ -1945,7 +1946,8 @@ static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) case F_SETFL: case ZFD_IOCTL_GETSOCKNAME: /* Pass the call to the core socket implementation. */ - return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args); + return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, + n_args, args); case ZFD_IOCTL_CLOSE: return ztls_close_ctx(obj); @@ -1955,9 +1957,9 @@ static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) struct k_poll_event **pev; struct k_poll_event *pev_end; - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); - pev_end = va_arg(args, struct k_poll_event *); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; + pev_end = (struct k_poll_event *)args[2]; return ztls_poll_prepare_ctx(obj, pfd, pev, pev_end); } @@ -1966,8 +1968,8 @@ static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args) struct zsock_pollfd *pfd; struct k_poll_event **pev; - pfd = va_arg(args, struct zsock_pollfd *); - pev = va_arg(args, struct k_poll_event **); + pfd = (struct zsock_pollfd *)args[0]; + pev = (struct k_poll_event **)args[1]; return ztls_poll_update_ctx(obj, pfd, pev); } diff --git a/subsys/net/lib/websocket/websocket.c b/subsys/net/lib/websocket/websocket.c index 7019a02cacb8d..0c12dd3c8e8da 100644 --- a/subsys/net/lib/websocket/websocket.c +++ b/subsys/net/lib/websocket/websocket.c @@ -417,7 +417,8 @@ int websocket_disconnect(int ws_sock) return ret; } -static int websocket_ioctl_vmeth(void *obj, unsigned int request, va_list args) +static int websocket_ioctl_vmeth(void *obj, unsigned long request, + long n_args, uintptr_t *args) { if (request == ZFD_IOCTL_CLOSE) { struct websocket_context *ctx = obj; @@ -434,7 +435,7 @@ static int websocket_ioctl_vmeth(void *obj, unsigned int request, va_list args) return ret; } - return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args); + return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, n_args, args); } static int websocket_prepare_and_send(struct websocket_context *ctx, diff --git a/tests/net/socket/socket_helpers.h b/tests/net/socket/socket_helpers.h index 69bb20c14b02a..e8bea92e3321b 100644 --- a/tests/net/socket/socket_helpers.h +++ b/tests/net/socket/socket_helpers.h @@ -6,7 +6,12 @@ #include +#ifdef CONFIG_POSIX_API +#include +#include +#else #include +#endif #define clear_buf(buf) memset(buf, 0, sizeof(buf)) diff --git a/tests/net/socket/tcp/src/main.c b/tests/net/socket/tcp/src/main.c index aa840c2168217..a4bb62ae015cf 100644 --- a/tests/net/socket/tcp/src/main.c +++ b/tests/net/socket/tcp/src/main.c @@ -11,6 +11,10 @@ LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL); #include #include +#ifdef CONFIG_POSIX_API +#include +#endif + #include "../../socket_helpers.h" #define TEST_STR_SMALL "test" @@ -50,6 +54,15 @@ static void test_send(int sock, const void *buf, size_t len, int flags) "send failed"); } +#ifdef CONFIG_POSIX_API +static void test_write(int sock, const void *buf, size_t len) +{ + zassert_equal(write(sock, buf, len), + len, + "write failed"); +} +#endif + static void test_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) { @@ -96,6 +109,22 @@ static void test_recv(int sock, int flags) "unexpected data"); } +#ifdef CONFIG_POSIX_API +static void test_read(int sock) +{ + ssize_t recved = 0; + char rx_buf[30] = {0}; + + recved = read(sock, rx_buf, sizeof(rx_buf)); + zassert_equal(recved, + strlen(TEST_STR_SMALL), + "unexpected received bytes"); + zassert_equal(strncmp(rx_buf, TEST_STR_SMALL, strlen(TEST_STR_SMALL)), + 0, + "unexpected data"); +} +#endif + static void test_recvfrom(int sock, int flags, struct sockaddr *addr, @@ -147,6 +176,7 @@ static void test_eof(int sock) zassert_equal(recved, 0, ""); } +/* Keep in sync with test_v4_write_read() below. */ void test_v4_send_recv(void) { /* Test if send() and recv() work on a ipv4 stream socket. */ @@ -184,6 +214,47 @@ void test_v4_send_recv(void) k_sleep(TCP_TEARDOWN_TIMEOUT); } +/* Keep in sync with test_v4_send_recv() above. */ +void test_v4_write_read(void) +{ +#ifndef CONFIG_POSIX_API + ztest_test_skip(); +#else + /* Test if send() and recv() work on a ipv4 stream socket. */ + int c_sock; + int s_sock; + int new_sock; + struct sockaddr_in c_saddr; + struct sockaddr_in s_saddr; + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + + prepare_sock_tcp_v4(CONFIG_NET_CONFIG_MY_IPV4_ADDR, ANY_PORT, + &c_sock, &c_saddr); + prepare_sock_tcp_v4(CONFIG_NET_CONFIG_MY_IPV4_ADDR, SERVER_PORT, + &s_sock, &s_saddr); + + test_bind(s_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_listen(s_sock); + + test_connect(c_sock, (struct sockaddr *)&s_saddr, sizeof(s_saddr)); + test_write(c_sock, TEST_STR_SMALL, strlen(TEST_STR_SMALL)); + + test_accept(s_sock, &new_sock, &addr, &addrlen); + zassert_equal(addrlen, sizeof(struct sockaddr_in), "wrong addrlen"); + + test_read(new_sock); + + test_close(c_sock); + test_eof(new_sock); + + test_close(new_sock); + test_close(s_sock); + + k_sleep(TCP_TEARDOWN_TIMEOUT); +#endif +} + void test_v6_send_recv(void) { /* Test if send() and recv() work on a ipv6 stream socket. */ @@ -516,6 +587,7 @@ void test_main(void) ztest_test_suite( socket_tcp, ztest_user_unit_test(test_v4_send_recv), + ztest_user_unit_test(test_v4_write_read), ztest_user_unit_test(test_v6_send_recv), ztest_user_unit_test(test_v4_sendto_recvfrom), ztest_user_unit_test(test_v6_sendto_recvfrom), diff --git a/tests/net/socket/tcp/testcase.yaml b/tests/net/socket/tcp/testcase.yaml index 8c64053dbc030..7661b813b120b 100644 --- a/tests/net/socket/tcp/testcase.yaml +++ b/tests/net/socket/tcp/testcase.yaml @@ -1,6 +1,11 @@ common: depends_on: netif + min_ram: 32 + tags: net socket userspace tests: net.socket.tcp: - min_ram: 32 - tags: net socket userspace + extra_configs: + - CONFIG_POSIX_API=n + net.socket.tcp.posix: + extra_configs: + - CONFIG_POSIX_API=y