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*/