Adds test cases 200x for TCP/UDP iSocket interface
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/host/xtest/Makefile b/host/xtest/Makefile
index a0661dd..af7298b 100644
--- a/host/xtest/Makefile
+++ b/host/xtest/Makefile
@@ -25,8 +25,15 @@
GP := _gp
endif
-srcs := xtest_1000.c \
- xtest_4000.c \
+srcs := xtest_1000.c
+
+ifeq ($(CFG_GP_SOCKETS),y)
+srcs += xtest_2000.c \
+ sock_server.c \
+ rand_stream.c
+endif
+
+srcs += xtest_4000.c \
xtest_5000.c \
xtest_6000.c \
xtest_7000$(GP).c \
@@ -46,6 +53,8 @@
adbg/src/adbg_run.c \
adbg/src/security_utils_hex.c
+CFLAGS += -D_GNU_SOURCE
+
ifdef CFG_GP_PACKAGE_PATH
CFLAGS += -DWITH_GP_TESTS
@@ -76,6 +85,7 @@
CFLAGS += -I../../ta/concurrent_large/include
CFLAGS += -I../../ta/sha_perf/include
CFLAGS += -I../../ta/aes_perf/include
+CFLAGS += -I../../ta/socket/include
ifdef CFG_GP_PACKAGE_PATH
CFLAGS += -I../../ta/GP_TTA_Arithmetical
CFLAGS += -I../../ta/GP_TTA_Crypto
diff --git a/host/xtest/rand_stream.c b/host/xtest/rand_stream.c
new file mode 100644
index 0000000..60ad920
--- /dev/null
+++ b/host/xtest/rand_stream.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include "rand_stream.h"
+
+#define STREAM_BUF_MIN_SIZE 4
+
+struct rand_stream {
+ struct random_data random_data;
+ char state_buf[128];
+ uint8_t word_buf[4];
+ size_t w_offs;
+ size_t sb_size;
+ size_t sb_offs;
+ uint8_t stream_buf[];
+};
+
+struct rand_stream *rand_stream_alloc(int seed, size_t stream_buffer_size)
+{
+ size_t sb_size = MAX(stream_buffer_size, STREAM_BUF_MIN_SIZE);
+ struct rand_stream *rs = calloc(1, sizeof(*rs) + sb_size);
+
+ if (!rs)
+ return NULL;
+
+ rs->sb_size = sb_size;;
+ rs->sb_offs = rs->sb_size;
+ rs->w_offs = sizeof(rs->word_buf);
+
+ if (initstate_r(seed, rs->state_buf, sizeof(rs->state_buf),
+ &rs->random_data)) {
+ free(rs);
+ return NULL;
+ }
+
+ return rs;
+}
+
+void rand_stream_free(struct rand_stream *rs)
+{
+ free(rs);
+}
+
+static void get_random(struct rand_stream *rs, uint8_t *buf, size_t blen)
+{
+ uint8_t *b = buf;
+ size_t l = blen;
+
+ while (l) {
+ size_t t = MIN(sizeof(rs->word_buf) - rs->w_offs, l);
+
+ memcpy(b, rs->word_buf + rs->w_offs, t);
+ rs->w_offs += t;
+ l -= t;
+ b += t;
+
+ if (rs->w_offs == sizeof(rs->word_buf)) {
+ int32_t r;
+
+ random_r(&rs->random_data, &r);
+ memcpy(rs->word_buf, &r, sizeof(r));
+ rs->w_offs = 0;
+ }
+ }
+}
+
+const void *rand_stream_peek(struct rand_stream *rs, size_t *num_bytes)
+{
+ if (rs->sb_offs == rs->sb_size) {
+ rs->sb_offs = 0;
+ get_random(rs, rs->stream_buf, rs->sb_size);
+ }
+
+ *num_bytes = MIN(*num_bytes, rs->sb_size - rs->sb_offs);
+ return rs->stream_buf + rs->sb_offs;
+}
+
+void rand_stream_read(struct rand_stream *rs, void *buf, size_t num_bytes)
+{
+ size_t peek_bytes = num_bytes;
+ const void *peek = rand_stream_peek(rs, &peek_bytes);
+
+ memcpy(buf, peek, peek_bytes);
+ rand_stream_advance(rs, peek_bytes);
+
+ if (num_bytes - peek_bytes)
+ get_random(rs, (uint8_t *)buf + peek_bytes,
+ num_bytes - peek_bytes);
+}
+
+void rand_stream_advance(struct rand_stream *rs, size_t num_bytes)
+{
+ size_t nb = num_bytes;
+
+ if (nb <= (rs->sb_size - rs->sb_offs)) {
+ rs->sb_offs += nb;
+ return;
+ }
+
+ nb -= rs->sb_size - rs->sb_offs;
+ rs->sb_offs = rs->sb_size;
+
+ while (nb > rs->sb_size) {
+ get_random(rs, rs->stream_buf, rs->sb_size);
+ nb -= rs->sb_size;
+ }
+
+ get_random(rs, rs->stream_buf, rs->sb_size);
+ rs->sb_offs = nb;
+}
diff --git a/host/xtest/rand_stream.h b/host/xtest/rand_stream.h
new file mode 100644
index 0000000..2c7db52
--- /dev/null
+++ b/host/xtest/rand_stream.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __RAND_STREAM_H
+#define __RAND_STREAM_H
+
+#include <sys/types.h>
+
+struct rand_stream;
+
+struct rand_stream *rand_stream_alloc(int seed, size_t stream_buffer_size);
+void rand_stream_free(struct rand_stream *rs);
+
+const void *rand_stream_peek(struct rand_stream *rs, size_t *num_bytes);
+void rand_stream_advance(struct rand_stream *rs, size_t num_bytes);
+void rand_stream_read(struct rand_stream *rs, void *buf, size_t num_bytes);
+
+#endif /*__RAND_STREAM_H*/
diff --git a/host/xtest/sock_server.c b/host/xtest/sock_server.c
new file mode 100644
index 0000000..0d2ff06
--- /dev/null
+++ b/host/xtest/sock_server.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <arpa/inet.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "sock_server.h"
+
+struct server_state {
+ struct sock_state *socks;
+ struct pollfd *fds;
+ nfds_t nfds;
+ bool got_quit;
+ struct sock_io_cb *cb;
+};
+
+#define SOCK_BUF_SIZE 512
+
+struct sock_state {
+ bool (*cb)(struct server_state *srvst, size_t idx);
+ struct sock_server_bind *serv;
+};
+
+static bool server_io_cb(struct server_state *srvst, size_t idx)
+{
+ short revents = srvst->fds[idx].revents;
+ short *events = &srvst->fds[idx].events;
+ struct sock_io_cb *cb = srvst->cb;
+ int fd;
+
+ fd = srvst->fds[idx].fd;
+ if (revents & POLLIN) {
+ if (!cb->read)
+ *events &= ~POLLIN;
+ else if (!cb->read(cb->ptr, fd, events))
+ goto close;
+ }
+
+ if (revents & POLLOUT) {
+ if (!cb->write)
+ *events &= ~POLLOUT;
+ else if (!cb->write(cb->ptr, fd, events))
+ goto close;
+ }
+
+ if (!(revents & ~(POLLIN | POLLOUT)))
+ return true;
+close:
+ if (close(fd)) {
+ warn("server_io_cb: close(%d)", fd);
+ return false;
+ }
+ srvst->fds[idx].fd = -1;
+ return true;
+}
+
+static bool server_add_state(struct server_state *srvst,
+ bool (*cb)(struct server_state *srvst, size_t idx),
+ struct sock_server_bind *serv, int fd,
+ short poll_events)
+{
+ void *p;
+ size_t n;
+
+ for (n = 0; n < srvst->nfds; n++) {
+ if (srvst->fds[n].fd == -1) {
+ srvst->socks[n].cb = cb;
+ srvst->socks[n].serv = serv;
+ srvst->fds[n].fd = fd;
+ srvst->fds[n].events = poll_events;
+ srvst->fds[n].revents = 0;
+ return true;
+ }
+ }
+
+ p = realloc(srvst->socks, sizeof(*srvst->socks) * (srvst->nfds + 1));
+ if (!p)
+ return false;
+ srvst->socks = p;
+ srvst->socks[srvst->nfds].cb = cb;
+ srvst->socks[srvst->nfds].serv = serv;
+
+ p = realloc(srvst->fds, sizeof(*srvst->fds) * (srvst->nfds + 1));
+ if (!p)
+ return false;
+ srvst->fds = p;
+ srvst->fds[srvst->nfds].fd = fd;
+ srvst->fds[srvst->nfds].events = poll_events;
+ srvst->fds[srvst->nfds].revents = 0;
+
+ srvst->nfds++;
+ return true;
+}
+
+static bool tcp_server_accept_cb(struct server_state *srvst, size_t idx)
+{
+ short revents = srvst->fds[idx].revents;
+ struct sockaddr_storage sass;
+ struct sockaddr *sa = (struct sockaddr *)&sass;
+ socklen_t len = sizeof(sass);
+ int fd;
+ short io_events = POLLIN | POLLOUT;
+
+ if (!(revents & POLLIN))
+ return false;
+
+ fd = accept(srvst->fds[idx].fd, sa, &len);
+ if (fd == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == ECONNABORTED)
+ return true;
+ return false;
+ }
+
+ if (srvst->cb->accept &&
+ !srvst->cb->accept(srvst->cb->ptr, fd, &io_events)) {
+ if (close(fd))
+ warn("server_accept_cb: close(%d)", fd);
+ return true;
+ }
+
+ return server_add_state(srvst, server_io_cb, srvst->socks[idx].serv,
+ fd, io_events);
+}
+
+static bool udp_server_cb(struct server_state *srvst, size_t idx)
+{
+ short revents = srvst->fds[idx].revents;
+
+ if (!(revents & POLLIN))
+ return false;
+
+ return srvst->cb->accept(srvst->cb->ptr, srvst->fds[idx].fd, NULL);
+}
+
+static bool server_quit_cb(struct server_state *srvst, size_t idx)
+{
+ (void)idx;
+ srvst->got_quit = true;
+ return true;
+}
+
+static void sock_server(struct sock_server *ts,
+ bool (*cb)(struct server_state *srvst, size_t idx))
+{
+ struct server_state srvst = { .cb = ts->cb };
+ int pres;
+ size_t n;
+ char b;
+
+ sock_server_lock(ts);
+
+ for (n = 0; n < ts->num_binds; n++) {
+ if (!server_add_state(&srvst, cb, ts->bind + n,
+ ts->bind[n].fd, POLLIN))
+ goto bad;
+ }
+
+ if (!server_add_state(&srvst, server_quit_cb, NULL,
+ ts->quit_fd, POLLIN))
+ goto bad;
+
+ while (true) {
+ sock_server_unlock(ts);
+ /*
+ * First sleep 5 ms to make it easier to test send timeouts
+ * due to this rate limit.
+ */
+ poll(NULL, 0, 5);
+ pres = poll(srvst.fds, srvst.nfds, -1);
+ sock_server_lock(ts);
+ if (pres < 0)
+ goto bad;
+
+ for (n = 0; pres && n < srvst.nfds; n++) {
+ if (srvst.fds[n].revents) {
+ pres--;
+ if (!srvst.socks[n].cb(&srvst, n))
+ goto bad;
+ }
+ }
+
+ if (srvst.got_quit)
+ goto out;
+ }
+
+bad:
+ ts->error = true;
+out:
+ for (n = 0; n < srvst.nfds; n++) {
+ /* Don't close accept and quit fds */
+ if (srvst.fds[n].fd != -1 && srvst.socks[n].serv &&
+ srvst.fds[n].fd != srvst.socks[n].serv->fd) {
+ if (close(srvst.fds[n].fd))
+ warn("sock_server: close(%d)", srvst.fds[n].fd);
+ }
+ }
+ free(srvst.socks);
+ free(srvst.fds);
+ if (read(ts->quit_fd, &b, 1) != 1)
+ ts->error = true;
+
+ sock_server_unlock(ts);
+}
+
+static void *sock_server_stream(void *arg)
+{
+ sock_server(arg, tcp_server_accept_cb);
+ return NULL;
+}
+
+static void *sock_server_dgram(void *arg)
+{
+ sock_server(arg, udp_server_cb);
+ return NULL;
+}
+
+static void sock_server_add_fd(struct sock_server *ts, struct addrinfo *ai)
+{
+ struct sock_server_bind serv;
+ struct sockaddr_storage sass;
+ struct sockaddr *sa = (struct sockaddr *)&sass;
+ struct sockaddr_in *sain = (struct sockaddr_in *)&sass;
+ struct sockaddr_in6 *sain6 = (struct sockaddr_in6 *)&sass;
+ void *src;
+ socklen_t len = sizeof(sass);
+ struct sock_server_bind *p;
+
+ memset(&serv, 0, sizeof(serv));
+
+ serv.fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (serv.fd < 0)
+ return;
+
+ if (bind(serv.fd, ai->ai_addr, ai->ai_addrlen))
+ goto bad;
+
+ if (ai->ai_socktype == SOCK_STREAM && listen(serv.fd, 5))
+ goto bad;
+
+ if (getsockname(serv.fd, sa, &len))
+ goto bad;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ src = &sain->sin_addr;
+ serv.port = ntohs(sain->sin_port);
+ break;
+ case AF_INET6:
+ src = &sain6->sin6_addr;
+ serv.port = ntohs(sain6->sin6_port);
+ default:
+ goto bad;
+ }
+
+ if (!inet_ntop(sa->sa_family, src, serv.host, sizeof(serv.host)))
+ goto bad;
+
+ p = realloc(ts->bind, sizeof(*p) * (ts->num_binds + 1));
+ if (!p)
+ goto bad;
+
+ ts->bind = p;
+ p[ts->num_binds] = serv;
+ ts->num_binds++;
+ return;
+bad:
+ if (close(serv.fd))
+ warn("sock_server_add_fd: close(%d)", serv.fd);
+}
+
+void sock_server_uninit(struct sock_server *ts)
+{
+ size_t n;
+ int e;
+
+ if (ts->stop_fd != -1) {
+ if (close(ts->stop_fd))
+ warn("sock_server_uninit: close(%d)", ts->stop_fd);
+ ts->stop_fd = -1;
+ e = pthread_join(ts->thr, NULL);
+ if (e)
+ warnx("sock_server_uninit: pthread_join: %s",
+ strerror(e));
+ }
+
+ e = pthread_mutex_destroy(&ts->mu);
+ if (e)
+ warnx("sock_server_uninit: pthread_mutex_destroy: %s",
+ strerror(e));
+
+ for (n = 0; n < ts->num_binds; n++)
+ if (close(ts->bind[n].fd))
+ warn("sock_server_uninit: close(%d)", ts->bind[n].fd);
+ free(ts->bind);
+ if (ts->quit_fd != -1 && close(ts->quit_fd))
+ warn("sock_server_uninit: close(%d)", ts->quit_fd);
+ memset(ts, 0, sizeof(*ts));
+ ts->quit_fd = -1;
+ ts->stop_fd = -1;
+}
+
+static bool sock_server_init(struct sock_server *ts, struct sock_io_cb *cb,
+ int socktype)
+{
+ struct addrinfo hints;
+ struct addrinfo *ai;
+ struct addrinfo *ai0;
+ int fd_pair[2];
+ int e;
+
+ memset(ts, 0, sizeof(*ts));
+ ts->quit_fd = -1;
+ ts->stop_fd = -1;
+ ts->cb = cb;
+
+ e = pthread_mutex_init(&ts->mu, NULL);
+ if (e) {
+ warnx("sock_server_init: pthread_mutex_init: %s", strerror(e));
+ return false;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = socktype;
+
+ if (getaddrinfo(NULL, "0", &hints, &ai0))
+ return false;
+
+ for (ai = ai0; ai; ai = ai->ai_next)
+ sock_server_add_fd(ts, ai);
+
+ if (!ts->num_binds)
+ return false;
+
+ if (pipe(fd_pair)) {
+ sock_server_uninit(ts);
+ return false;
+ }
+
+ ts->quit_fd = fd_pair[0];
+
+ if (socktype == SOCK_STREAM)
+ e = pthread_create(&ts->thr, NULL, sock_server_stream, ts);
+ else
+ e = pthread_create(&ts->thr, NULL, sock_server_dgram, ts);
+ if (e) {
+ warnx("sock_server_init: pthread_create: %s", strerror(e));
+ if (close(fd_pair[1]))
+ warn("sock_server_init: close(%d)", fd_pair[1]);
+ sock_server_uninit(ts);
+ return false;
+ }
+
+ ts->stop_fd = fd_pair[1];
+ return true;
+}
+
+bool sock_server_init_tcp(struct sock_server *sock_serv, struct sock_io_cb *cb)
+{
+ return sock_server_init(sock_serv, cb, SOCK_STREAM);
+}
+
+bool sock_server_init_udp(struct sock_server *sock_serv, struct sock_io_cb *cb)
+{
+ return sock_server_init(sock_serv, cb, SOCK_DGRAM);
+}
+
+void sock_server_lock(struct sock_server *ts)
+{
+ int e = pthread_mutex_lock(&ts->mu);
+
+ if (e)
+ errx(1, "sock_server_lock: pthread_mutex_lock: %s", strerror(e));
+}
+
+void sock_server_unlock(struct sock_server *ts)
+{
+ int e = pthread_mutex_unlock(&ts->mu);
+
+ if (e)
+ errx(1, "sock_server_unlock: pthread_mutex_unlock: %s",
+ strerror(e));
+}
diff --git a/host/xtest/sock_server.h b/host/xtest/sock_server.h
new file mode 100644
index 0000000..bd91271
--- /dev/null
+++ b/host/xtest/sock_server.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef XTEST_SOCK_SERVER_H
+#define XTEST_SOCK_SERVER_H
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+struct sock_server_bind {
+ int fd;
+ char host[255];
+ int port;
+};
+
+struct sock_server {
+ struct sock_server_bind *bind;
+ size_t num_binds;
+ int quit_fd;
+ int stop_fd;
+ pthread_t thr;
+ pthread_mutex_t mu;
+ bool error;
+ struct sock_io_cb *cb;
+};
+
+struct sock_io_cb {
+ bool (*accept)(void *ptr, int fd, short *events);
+ bool (*read)(void *ptr, int fd, short *events);
+ bool (*write)(void *ptr, int fd, short *events);
+ void *ptr;
+};
+
+bool sock_server_init_tcp(struct sock_server *sock_serv, struct sock_io_cb *cb);
+bool sock_server_init_udp(struct sock_server *sock_serv, struct sock_io_cb *cb);
+void sock_server_uninit(struct sock_server *sock_serv);
+void sock_server_lock(struct sock_server *sock_serv);
+void sock_server_unlock(struct sock_server *sock_serv);
+
+#endif /*XTEST_SOCK_SERVER_H*/
diff --git a/host/xtest/xtest_2000.c b/host/xtest/xtest_2000.c
new file mode 100644
index 0000000..3cba3ee
--- /dev/null
+++ b/host/xtest/xtest_2000.c
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <assert.h>
+#include <err.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <ta_socket.h>
+#include <tee_isocket.h>
+#include <tee_tcpsocket.h>
+#include <__tee_tcpsocket_defines_extensions.h>
+#include <tee_udpsocket.h>
+#include <unistd.h>
+
+#include "xtest_test.h"
+#include "xtest_helpers.h"
+#include "sock_server.h"
+#include "rand_stream.h"
+
+struct socket_handle {
+ uint64_t buf[2];
+ size_t blen;
+};
+
+static TEE_Result socket_tcp_open(TEEC_Session *session, uint32_t ip_vers,
+ const char *addr, uint16_t port,
+ struct socket_handle *handle,
+ uint32_t *error, uint32_t *ret_orig)
+{
+ TEE_Result res;
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ memset(handle, 0, sizeof(*handle));
+
+ op.params[0].value.a = ip_vers;
+ op.params[0].value.b = port;
+ op.params[1].tmpref.buffer = (void *)addr;
+ op.params[1].tmpref.size = strlen(addr) + 1;
+ op.params[2].tmpref.buffer = handle->buf;
+ op.params[2].tmpref.size = sizeof(handle->buf);
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+ TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_OUTPUT,
+ TEEC_VALUE_OUTPUT);
+
+ res = TEEC_InvokeCommand(session, TA_SOCKET_CMD_TCP_OPEN,
+ &op, ret_orig);
+
+ handle->blen = op.params[2].tmpref.size;
+ *error = op.params[3].value.a;
+ return res;
+}
+
+static TEE_Result socket_udp_open(TEEC_Session *session, uint32_t ip_vers,
+ const char *addr, uint16_t port,
+ struct socket_handle *handle,
+ uint32_t *error, uint32_t *ret_orig)
+{
+ TEE_Result res;
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ memset(handle, 0, sizeof(*handle));
+
+ op.params[0].value.a = ip_vers;
+ op.params[0].value.b = port;
+ op.params[1].tmpref.buffer = (void *)addr;
+ op.params[1].tmpref.size = strlen(addr) + 1;
+ op.params[2].tmpref.buffer = handle->buf;
+ op.params[2].tmpref.size = sizeof(handle->buf);
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+ TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_OUTPUT,
+ TEEC_VALUE_OUTPUT);
+
+ res = TEEC_InvokeCommand(session, TA_SOCKET_CMD_UDP_OPEN,
+ &op, ret_orig);
+
+ handle->blen = op.params[2].tmpref.size;
+ *error = op.params[3].value.a;
+ return res;
+}
+
+static TEE_Result socket_send(TEEC_Session *session,
+ struct socket_handle *handle,
+ const void *data, size_t *dlen,
+ uint32_t timeout, uint32_t *ret_orig)
+{
+ TEE_Result res;
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ op.params[0].tmpref.buffer = handle->buf;
+ op.params[0].tmpref.size = handle->blen;
+ op.params[1].tmpref.buffer = (void *)data;
+ op.params[1].tmpref.size = *dlen;
+ op.params[2].value.a = timeout;
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_INPUT,
+ TEEC_VALUE_INOUT, TEEC_NONE);
+
+ res = TEEC_InvokeCommand(session, TA_SOCKET_CMD_SEND, &op, ret_orig);
+
+ *dlen = op.params[2].value.b;
+ return res;
+}
+
+static TEE_Result socket_recv(TEEC_Session *session,
+ struct socket_handle *handle,
+ void *data, size_t *dlen,
+ uint32_t timeout, uint32_t *ret_orig)
+{
+ TEE_Result res;
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ op.params[0].tmpref.buffer = handle->buf;
+ op.params[0].tmpref.size = handle->blen;
+ op.params[1].tmpref.buffer = (void *)data;
+ op.params[1].tmpref.size = *dlen;
+ op.params[2].value.a = timeout;
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_OUTPUT,
+ TEEC_VALUE_INPUT, TEEC_NONE);
+
+ res = TEEC_InvokeCommand(session, TA_SOCKET_CMD_RECV, &op, ret_orig);
+
+ *dlen = op.params[1].tmpref.size;
+ return res;
+}
+
+static TEE_Result socket_get_error(TEEC_Session *session,
+ struct socket_handle *handle,
+ uint32_t *proto_error, uint32_t *ret_orig)
+{
+ TEE_Result res;
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ op.params[0].tmpref.buffer = handle->buf;
+ op.params[0].tmpref.size = handle->blen;
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_VALUE_OUTPUT,
+ TEEC_NONE, TEEC_NONE);
+
+ res = TEEC_InvokeCommand(session, TA_SOCKET_CMD_ERROR, &op, ret_orig);
+
+ *proto_error = op.params[1].value.a;
+ return res;
+}
+
+static TEE_Result socket_close(TEEC_Session *session,
+ struct socket_handle *handle, uint32_t *ret_orig)
+{
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ op.params[0].tmpref.buffer = handle->buf;
+ op.params[0].tmpref.size = handle->blen;
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_NONE, TEEC_NONE, TEEC_NONE);
+
+ return TEEC_InvokeCommand(session, TA_SOCKET_CMD_CLOSE, &op, ret_orig);
+}
+
+static TEE_Result socket_ioctl(TEEC_Session *session,
+ struct socket_handle *handle, uint32_t ioctl_cmd,
+ void *data, size_t *dlen, uint32_t *ret_orig)
+{
+ TEE_Result res;
+ TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+ op.params[0].tmpref.buffer = handle->buf;
+ op.params[0].tmpref.size = handle->blen;
+ op.params[1].tmpref.buffer = data;
+ op.params[1].tmpref.size = *dlen;
+ op.params[2].value.a = ioctl_cmd;
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_INOUT,
+ TEEC_VALUE_INPUT, TEEC_NONE);
+
+ res = TEEC_InvokeCommand(session, TA_SOCKET_CMD_IOCTL, &op, ret_orig);
+
+ *dlen = op.params[1].tmpref.size;
+ return res;
+}
+
+
+
+struct test_200x_io_state {
+ struct rand_stream *read_rs;
+ struct rand_stream *write_rs;
+ bool rfail;
+};
+
+static void test_200x_init_io_state(struct test_200x_io_state *s,
+ int read_seed, int write_seed)
+{
+ memset(s, 0, sizeof(*s));
+ s->read_rs = rand_stream_alloc(read_seed, 100);
+ s->write_rs = rand_stream_alloc(write_seed, 100);
+ assert(s->read_rs && s->write_rs);
+}
+
+static bool test_200x_tcp_accept_cb(void *ptr, int fd, short *events)
+{
+ (void)ptr;
+ (void)fd;
+ (void)events;
+ return true;
+}
+
+static bool test_200x_tcp_read_cb(void *ptr, int fd, short *events)
+{
+ struct test_200x_io_state *iostate = ptr;
+ ssize_t r;
+ uint8_t buf[100];
+ uint8_t buf2[100];
+
+ (void)events;
+ r = read(fd, buf, sizeof(buf));
+ if (r <= 0)
+ return false;
+
+ rand_stream_read(iostate->read_rs, buf2, r);
+ if (memcmp(buf, buf2, r)) {
+ iostate->rfail = true;
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_200x_tcp_write_cb(void *ptr, int fd, short *events)
+{
+ struct test_200x_io_state *iostate = ptr;
+ size_t num_bytes = 100;
+ const void *bytes;
+ ssize_t r;
+
+ (void)events;
+
+ bytes = rand_stream_peek(iostate->write_rs, &num_bytes);
+ r = write(fd, bytes, num_bytes);
+ if (r < 0)
+ return false;
+
+ rand_stream_advance(iostate->write_rs, num_bytes);
+ return true;
+}
+
+static void xtest_tee_test_2001(ADBG_Case_t *c)
+{
+ struct sock_server ts;
+ TEEC_Session session = { 0 };
+ uint32_t ret_orig;
+ uint32_t proto_error;
+ struct socket_handle sh;
+ uint8_t buf[64];
+ uint8_t buf2[64];
+ size_t blen;
+ struct test_200x_io_state server_iostate;
+ struct test_200x_io_state local_iostate;
+ struct sock_io_cb cb = {
+ .accept = test_200x_tcp_accept_cb,
+ .read = test_200x_tcp_read_cb,
+ .write = test_200x_tcp_write_cb,
+ .ptr = &server_iostate,
+ };
+
+ test_200x_init_io_state(&server_iostate, 1, 2);
+ test_200x_init_io_state(&local_iostate, 2, 1);
+
+ Do_ADBG_BeginSubCase(c, "Start server");
+ if (!ADBG_EXPECT_TRUE(c, sock_server_init_tcp(&ts, &cb)))
+ return;
+ Do_ADBG_EndSubCase(c, "Start server");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket open");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_tcp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ Do_ADBG_EndSubCase(c, "TCP Socket open");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket send");
+ blen = sizeof(buf);
+ rand_stream_read(local_iostate.write_rs, buf, blen);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_send(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ Do_ADBG_EndSubCase(c, "TCP Socket send");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket recv");
+ blen = sizeof(buf);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_recv(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ rand_stream_read(local_iostate.read_rs, buf2, blen);
+ ADBG_EXPECT_BUFFER(c, buf2, blen, buf, blen);
+ Do_ADBG_EndSubCase(c, "TCP Socket recv");
+
+ /*
+ * All written bytes above (with the TA) is quite likely to have
+ * hit the tcp server by now.
+ */
+ ADBG_EXPECT_TRUE(c, !server_iostate.rfail);
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket get error");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_get_error(&session, &sh,
+ &proto_error, &ret_orig)))
+ goto out_close_session;
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, proto_error))
+ goto out_close_session;
+ Do_ADBG_EndSubCase(c, "TCP Socket get error");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket close");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_close(&session, &sh,
+ &ret_orig)))
+ goto out_close_session;
+ Do_ADBG_EndSubCase(c, "TCP Socket close");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket ioctl");
+
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_tcp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(buf);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh, 0x00F00000,
+ buf, &blen, &ret_orig)))
+ goto out_close_session;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_close(&session, &sh,
+ &ret_orig)))
+ goto out_close_session;
+
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_tcp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(buf);
+ ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_TARGET_DEAD,
+ socket_ioctl(&session, &sh,
+ TEE_ISOCKET_PROTOCOLID_TCP << 24,
+ buf, &blen, &ret_orig));
+ TEEC_CloseSession(&session);
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_tcp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(buf);
+ ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_TARGET_DEAD,
+ socket_ioctl(&session, &sh, 0x32 << 24,
+ buf, &blen, &ret_orig));
+
+ Do_ADBG_EndSubCase(c, "TCP Socket ioctl");
+
+out_close_session:
+ TEEC_CloseSession(&session);
+out:
+ sock_server_uninit(&ts);
+}
+
+struct test_2002_barrier {
+ pthread_mutex_t mu;
+ pthread_barrier_t bar;
+};
+
+struct test_2002_arg {
+ bool success;
+ size_t tnum;
+ struct test_2002_barrier *bar;
+};
+
+static void xtest_2002_wait_barrier(struct test_2002_barrier *bar)
+{
+ /*
+ * Once the mutex is taken the barrier is initialized so the mutex
+ * can be released immediately.
+ */
+ xtest_mutex_lock(&bar->mu);
+ xtest_mutex_unlock(&bar->mu);
+ xtest_barrier_wait(&bar->bar);
+}
+
+static void *xtest_tee_test_2002_thread(void *arg)
+{
+ struct test_2002_arg *a = arg;
+ TEE_Result res;
+ struct sock_server ts;
+ TEEC_Session session = { 0 };
+ uint32_t ret_orig;
+ uint32_t proto_error;
+ struct socket_handle sh;
+ struct test_200x_io_state server_iostate;
+ struct test_200x_io_state local_iostate;
+ struct sock_io_cb cb = {
+ .accept = test_200x_tcp_accept_cb,
+ .read = test_200x_tcp_read_cb,
+ .write = test_200x_tcp_write_cb,
+ .ptr = &server_iostate,
+ };
+ int seed[2] = { 1 + a->tnum * 2, 2 + a->tnum * 2 };
+ size_t send_limit = 10000;
+ size_t recv_limit = 10000;
+ size_t sent_bytes = 0;
+ size_t recvd_bytes = 0;
+
+ test_200x_init_io_state(&server_iostate, seed[0], seed[1]);
+ test_200x_init_io_state(&local_iostate, seed[1], seed[0]);
+
+ if (!sock_server_init_tcp(&ts, &cb)) {
+ xtest_2002_wait_barrier(a->bar);
+ return NULL;
+ }
+
+ res = xtest_teec_open_session(&session, &socket_ta_uuid, NULL,
+ &ret_orig);
+
+ xtest_2002_wait_barrier(a->bar);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = socket_tcp_open(&session, TEE_IP_VERSION_DC, ts.bind->host,
+ ts.bind->port, &sh, &proto_error, &ret_orig);
+ if (res != TEE_SUCCESS)
+ goto out_close_session;
+
+ while (sent_bytes < send_limit && recvd_bytes < recv_limit) {
+ const void *peek;
+ uint8_t buf[64];
+ uint8_t buf2[64];
+ size_t blen;
+
+ blen = sizeof(buf);
+ peek = rand_stream_peek(local_iostate.write_rs, &blen);
+ res = socket_send(&session, &sh, peek, &blen,
+ TEE_TIMEOUT_INFINITE, &ret_orig);
+ if (res != TEE_SUCCESS)
+ goto out_close_session;
+ rand_stream_advance(local_iostate.write_rs, blen);
+ sent_bytes += blen;
+
+ blen = sizeof(buf);
+ res = socket_recv(&session, &sh, buf, &blen,
+ TEE_TIMEOUT_INFINITE, &ret_orig);
+ if (res != TEE_SUCCESS)
+ goto out_close_session;
+ rand_stream_read(local_iostate.read_rs, buf2, blen);
+ if (memcmp(buf2, buf, blen))
+ goto out_close_session;
+ recvd_bytes += blen;
+ }
+
+
+ res = socket_close(&session, &sh, &ret_orig);
+ if (res != TEE_SUCCESS)
+ goto out_close_session;
+
+ /*
+ * All written bytes above (with the TA) is quite likely to have
+ * hit the tcp server by now.
+ */
+ a->success = !server_iostate.rfail;
+
+out_close_session:
+ TEEC_CloseSession(&session);
+out:
+ sock_server_uninit(&ts);
+ return NULL;
+}
+
+#define NUM_THREADS 3
+
+static void xtest_tee_test_2002(ADBG_Case_t *c)
+{
+ pthread_t thr[NUM_THREADS];
+ struct test_2002_barrier bar = { .mu = PTHREAD_MUTEX_INITIALIZER };
+ struct test_2002_arg arg[NUM_THREADS];
+ size_t n;
+ size_t nt;
+
+ Do_ADBG_BeginSubCase(c, "Stressing with %d threads", NUM_THREADS);
+
+ xtest_mutex_lock(&bar.mu);
+
+ nt = NUM_THREADS;
+ for (n = 0; n < nt; n++) {
+ arg[n].success = false;
+ arg[n].tnum = n;
+ arg[n].bar = &bar;
+ if (!ADBG_EXPECT(c, 0, pthread_create(thr + n, NULL,
+ xtest_tee_test_2002_thread, arg + n)))
+ nt = n; /* break loop and start cleanup */
+ }
+
+ xtest_barrier_init(&bar.bar, nt + 1);
+ xtest_mutex_unlock(&bar.mu);
+ xtest_barrier_wait(&bar.bar);
+
+ for (n = 0; n < nt; n++) {
+ ADBG_EXPECT(c, 0, pthread_join(thr[n], NULL));
+ ADBG_EXPECT_TRUE(c, arg[n].success);
+ }
+
+ xtest_mutex_destroy(&bar.mu);
+ xtest_barrier_destroy(&bar.bar);
+
+ Do_ADBG_EndSubCase(c, "Stressing with %d threads", NUM_THREADS);
+}
+
+static bool test_2003_accept_cb(void *ptr, int fd, short *events)
+{
+ int val;
+
+ (void)ptr;
+ (void)events;
+
+ val = 4 * 1024;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)))
+ warn("test_2003_accept_cb: setsockopt");
+ return true;
+}
+
+static void xtest_tee_test_2003(ADBG_Case_t *c)
+{
+ struct sock_server ts;
+ TEEC_Session session = { 0 };
+ uint32_t ret_orig;
+ uint32_t proto_error;
+ struct socket_handle sh;
+ void *buf;
+ const size_t blen0 = 16 * 1024;
+ size_t blen;
+ uint32_t val;
+ struct sock_io_cb cb = { .accept = test_2003_accept_cb };
+
+ Do_ADBG_BeginSubCase(c, "Start server");
+ if (!ADBG_EXPECT_TRUE(c, sock_server_init_tcp(&ts, &cb)))
+ return;
+ buf = calloc(1, blen0);
+ if (!ADBG_EXPECT_NOT_NULL(c, buf))
+ goto out;
+ Do_ADBG_EndSubCase(c, "Start server");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket open");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_tcp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(val);
+ val = 4 * 1024;
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh,
+ TEE_TCP_SET_RECVBUF, &val, &blen, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(val);
+ val = 4 * 1024;
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh,
+ TEE_TCP_SET_SENDBUF, &val, &blen, &ret_orig)))
+ goto out_close_session;
+
+ Do_ADBG_EndSubCase(c, "TCP Socket open");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket send (10 ms timeout)");
+ while (true) {
+ TEE_Result res;
+
+ blen = blen0;
+ memset(buf, 0, blen0);
+ res = socket_send(&session, &sh, buf, &blen, 10, &ret_orig);
+ if (res == TEE_ISOCKET_ERROR_TIMEOUT)
+ break;
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, res))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, blen0);
+ }
+ Do_ADBG_EndSubCase(c, "TCP Socket send (10 ms timeout)");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket recv (10 ms timeout)");
+ blen = blen0;
+ ADBG_EXPECT_TEEC_RESULT(c, TEE_ISOCKET_ERROR_TIMEOUT,
+ socket_recv(&session, &sh, buf, &blen,
+ 10, &ret_orig));
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, blen0);
+ Do_ADBG_EndSubCase(c, "TCP Socket recv (10 ms timeout)");
+
+ Do_ADBG_BeginSubCase(c, "TCP Socket get error");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_get_error(&session, &sh,
+ &proto_error, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_TEEC_RESULT(c, TEE_ISOCKET_ERROR_TIMEOUT, proto_error);
+ Do_ADBG_EndSubCase(c, "TCP Socket get error");
+
+out_close_session:
+ TEEC_CloseSession(&session);
+out:
+ free(buf);
+ sock_server_uninit(&ts);
+}
+
+static bool test_200x_udp_accept_cb(void *ptr, int fd, short *events)
+{
+ struct test_200x_io_state *iostate = ptr;
+ struct sockaddr_storage sass;
+ struct sockaddr *sa = (struct sockaddr *)&sass;
+ socklen_t slen = sizeof(sass);
+ uint8_t buf[100];
+ uint8_t buf2[100];
+ ssize_t r;
+ size_t l;
+
+ (void)events;
+
+ r = recvfrom(fd, buf, sizeof(buf), 0, sa, &slen);
+ if (r == -1)
+ return false;
+
+ l = r;
+ rand_stream_read(iostate->read_rs, buf2, l);
+ if (memcmp(buf, buf2, l))
+ iostate->rfail = true;
+
+ rand_stream_read(iostate->write_rs, buf, l);
+ return sendto(fd, buf, l, 0, sa, slen) != -1;
+}
+
+static void xtest_tee_test_2004(ADBG_Case_t *c)
+{
+ struct sock_server ts;
+ struct sock_server ts2;
+ struct sock_server ts3;
+ bool ts_inited = false;
+ bool ts2_inited = false;
+ bool ts3_inited = false;
+ TEEC_Session session = { 0 };
+ uint32_t ret_orig;
+ uint32_t proto_error;
+ struct socket_handle sh;
+ uint8_t buf[64];
+ uint8_t buf2[64];
+ size_t blen;
+ uint16_t port;
+ struct test_200x_io_state server_iostate;
+ struct test_200x_io_state local_iostate;
+ struct sock_io_cb cb = {
+ .accept = test_200x_udp_accept_cb,
+ .ptr = &server_iostate,
+ };
+
+ test_200x_init_io_state(&server_iostate, 1, 2);
+ test_200x_init_io_state(&local_iostate, 2, 1);
+
+ Do_ADBG_BeginSubCase(c, "Start server");
+ if (!ADBG_EXPECT_TRUE(c, sock_server_init_udp(&ts, &cb)))
+ return;
+ ts_inited = true;
+ if (!ADBG_EXPECT_TRUE(c, sock_server_init_udp(&ts2, &cb)))
+ goto out;
+ ts2_inited = true;
+ if (!ADBG_EXPECT_TRUE(c, sock_server_init_udp(&ts3, &cb)))
+ goto out;
+ ts3_inited = true;
+ Do_ADBG_EndSubCase(c, "Start server");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket open");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_udp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ Do_ADBG_EndSubCase(c, "UDP Socket open");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket send");
+ blen = sizeof(buf);
+ rand_stream_read(local_iostate.write_rs, buf, blen);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_send(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ Do_ADBG_EndSubCase(c, "UDP Socket send");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket recv");
+ blen = sizeof(buf);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_recv(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ rand_stream_read(local_iostate.read_rs, buf2, blen);
+ ADBG_EXPECT_BUFFER(c, buf2, blen, buf, blen);
+ ADBG_EXPECT_TRUE(c, !server_iostate.rfail);
+ Do_ADBG_EndSubCase(c, "UDP Socket recv");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket get error");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_get_error(&session, &sh,
+ &proto_error, &ret_orig)))
+ goto out_close_session;
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, proto_error))
+ goto out_close_session;
+ Do_ADBG_EndSubCase(c, "UDP Socket get error");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket close");
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_close(&session, &sh,
+ &ret_orig)))
+ goto out_close_session;
+ Do_ADBG_EndSubCase(c, "UDP Socket close");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket ioctl");
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_udp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(buf);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh, 0x00F00000,
+ buf, &blen, &ret_orig)))
+ goto out_close_session;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_close(&session, &sh,
+ &ret_orig)))
+ goto out_close_session;
+
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_udp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(buf);
+ ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_TARGET_DEAD,
+ socket_ioctl(&session, &sh,
+ TEE_ISOCKET_PROTOCOLID_UDP << 24,
+ buf, &blen, &ret_orig));
+ TEEC_CloseSession(&session);
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_udp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+
+ blen = sizeof(buf);
+ ADBG_EXPECT_TEEC_RESULT(c, TEEC_ERROR_TARGET_DEAD,
+ socket_ioctl(&session, &sh, 0x32 << 24,
+ buf, &blen, &ret_orig));
+
+ Do_ADBG_EndSubCase(c, "UDP Socket ioctl");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket change port");
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_udp_open(&session,
+ TEE_IP_VERSION_DC, ts.bind->host, ts.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+ sock_server_uninit(&ts);
+ ts_inited = false;
+
+ port = ts2.bind->port;
+ blen = sizeof(port);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh,
+ TEE_UDP_CHANGEPORT, &port, &blen, &ret_orig)))
+ goto out_close_session;
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket send");
+ blen = sizeof(buf);
+ rand_stream_read(local_iostate.write_rs, buf, blen);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_send(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ Do_ADBG_EndSubCase(c, "UDP Socket send");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket recv");
+ blen = sizeof(buf);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_recv(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ rand_stream_read(local_iostate.read_rs, buf2, blen);
+ ADBG_EXPECT_BUFFER(c, buf2, blen, buf, blen);
+ ADBG_EXPECT_TRUE(c, !server_iostate.rfail);
+ Do_ADBG_EndSubCase(c, "UDP Socket recv");
+
+ Do_ADBG_EndSubCase(c, "UDP Socket change port");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket change addr");
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, xtest_teec_open_session(
+ &session, &socket_ta_uuid, NULL, &ret_orig)))
+ goto out;
+
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_udp_open(&session,
+ TEE_IP_VERSION_DC, ts2.bind->host, ts2.bind->port,
+ &sh, &proto_error, &ret_orig)))
+ goto out_close_session;
+ sock_server_uninit(&ts2);
+ ts2_inited = false;
+
+ port = ts3.bind->port;
+ blen = sizeof(port);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh,
+ TEE_UDP_CHANGEPORT, &port, &blen, &ret_orig)))
+ goto out_close_session;
+
+ blen = strlen(ts3.bind->host) + 1;
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_ioctl(&session, &sh,
+ TEE_UDP_CHANGEADDR, ts3.bind->host, &blen, &ret_orig)))
+ goto out_close_session;
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket send");
+ blen = sizeof(buf);
+ rand_stream_read(local_iostate.write_rs, buf, blen);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_send(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ Do_ADBG_EndSubCase(c, "UDP Socket send");
+
+ Do_ADBG_BeginSubCase(c, "UDP Socket recv");
+ blen = sizeof(buf);
+ if (!ADBG_EXPECT_TEEC_SUCCESS(c, socket_recv(&session, &sh,
+ buf, &blen, TEE_TIMEOUT_INFINITE, &ret_orig)))
+ goto out_close_session;
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, blen, ==, sizeof(buf));
+ rand_stream_read(local_iostate.read_rs, buf2, blen);
+ ADBG_EXPECT_BUFFER(c, buf2, blen, buf, blen);
+ ADBG_EXPECT_TRUE(c, !server_iostate.rfail);
+ Do_ADBG_EndSubCase(c, "UDP Socket recv");
+
+ Do_ADBG_EndSubCase(c, "UDP Socket change addr");
+
+
+out_close_session:
+ TEEC_CloseSession(&session);
+out:
+ if (ts_inited)
+ sock_server_uninit(&ts);
+ if (ts2_inited)
+ sock_server_uninit(&ts2);
+ if (ts3_inited)
+ sock_server_uninit(&ts3);
+}
+
+
+
+ADBG_CASE_DEFINE(regression, 2001, xtest_tee_test_2001,
+ "Trivial TCP iSocket API tests");
+
+ADBG_CASE_DEFINE(regression, 2002, xtest_tee_test_2002,
+ "Concurrent stressing TCP iSocket API tests");
+
+ADBG_CASE_DEFINE(regression, 2003, xtest_tee_test_2003,
+ "Timeout TCP iSocket API tests");
+
+ADBG_CASE_DEFINE(regression, 2004, xtest_tee_test_2004,
+ "UDP iSocket API tests");
diff --git a/host/xtest/xtest_main.c b/host/xtest/xtest_main.c
index 3d51ac0..1b43361 100644
--- a/host/xtest/xtest_main.c
+++ b/host/xtest/xtest_main.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2016, Linaro Limited
* Copyright (c) 2014, STMicroelectronics International N.V.
*
* This program is free software; you can redistribute it and/or modify
@@ -11,6 +12,8 @@
* GNU General Public License for more details.
*/
+#include <err.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -63,6 +66,12 @@
opterr = 0;
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+ warn("signal(SIGPIPE, SIG_IGN)");
+
+ if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
+ warn("signal(SIGPIPE, SIG_IGN)");
+
if (argc > 1 && !strcmp(argv[1], "--sha-perf"))
return sha_perf_runner_cmd_parser(argc-1, &argv[1]);
else if (argc > 1 && !strcmp(argv[1], "--aes-perf"))
diff --git a/host/xtest/xtest_test.c b/host/xtest/xtest_test.c
index fa0d214..656136d 100644
--- a/host/xtest/xtest_test.c
+++ b/host/xtest/xtest_test.c
@@ -23,7 +23,11 @@
#include <ta_concurrent_large.h>
#include <enc_fs_key_manager_test.h>
#include <ta_storage_benchmark.h>
+#include <ta_socket.h>
#include <tee_api_defines.h>
+#include <__tee_isocket_defines.h>
+#include <__tee_tcpsocket_defines.h>
+#include <__tee_udpsocket_defines.h>
#ifdef WITH_GP_TESTS
#include <tee_api_types.h>
#include <TTA_DS_protocol.h>
@@ -59,7 +63,15 @@
ADBG_ENUM_TABLE_ENTRY(TEE_ERROR_MAC_INVALID),
ADBG_ENUM_TABLE_ENTRY(TEE_ERROR_SIGNATURE_INVALID),
ADBG_ENUM_TABLE_ENTRY(TEE_ERROR_TIME_NOT_SET),
-ADBG_ENUM_TABLE_ENTRY(TEE_ERROR_TIME_NEEDS_RESET)
+ADBG_ENUM_TABLE_ENTRY(TEE_ERROR_TIME_NEEDS_RESET),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_ERROR_PROTOCOL),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_ERROR_REMOTE_CLOSED),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_ERROR_TIMEOUT),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_ERROR_OUT_OF_RESOURCES),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_ERROR_LARGE_BUFFER),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_WARNING_PROTOCOL),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_ERROR_HOSTNAME),
+ADBG_ENUM_TABLE_ENTRY(TEE_ISOCKET_UDP_WARNING_UNKNOWN_OUT_OF_BAND)
ADBG_ENUM_TABLE_DEFINE_END(TEEC_Result);
ADBG_ENUM_TABLE_DEFINE_BEGIN(TEEC_ErrorOrigin)
@@ -91,6 +103,7 @@
const TEEC_UUID concurrent_ta_uuid = TA_CONCURRENT_UUID;
const TEEC_UUID concurrent_large_ta_uuid = TA_CONCURRENT_LARGE_UUID;
const TEEC_UUID storage_benchmark_ta_uuid = TA_STORAGE_BENCHMARK_UUID;
+const TEEC_UUID socket_ta_uuid = TA_SOCKET_UUID;
#ifdef WITH_GP_TESTS
const TEEC_UUID gp_tta_ds_uuid = TA_TTA_DS_UUID;
#endif
diff --git a/host/xtest/xtest_test.h b/host/xtest/xtest_test.h
index 0bc46a8..95c8b52 100644
--- a/host/xtest/xtest_test.h
+++ b/host/xtest/xtest_test.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2016, Linaro Limited
* Copyright (c) 2014, STMicroelectronics International N.V.
*
* This program is free software; you can redistribute it and/or modify
@@ -125,6 +126,7 @@
extern const TEEC_UUID concurrent_ta_uuid;
extern const TEEC_UUID concurrent_large_ta_uuid;
extern const TEEC_UUID storage_benchmark_ta_uuid;
+extern const TEEC_UUID socket_ta_uuid;
extern char *_device;
#endif /*XTEST_TEST_H*/