/* * Copyright (C) 2012-2017, Samsung Electronics Co., Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" #include "sysdep.h" #include "tz_iwsock.h" #include "tz_kthread_pool.h" #include "tzlog.h" #define MAX_CONNECTION_ATTEMPTS 20 #define CONNECTION_ATTEMPT_TIMEOUT 100 int tzdev_teec_connect(struct sock_desc *socket, char *name, uint32_t *result, uint32_t *origin) { int ret; unsigned int attempt; *origin = TEEC_ORIGIN_COMMS; *result = TEEC_SUCCESS; for (attempt = 0; attempt < MAX_CONNECTION_ATTEMPTS; attempt++) { ret = tz_iwsock_connect(socket, name, 0); if (ret == 0) return ret; tzdev_teec_info("Failed to connect to %s socket, error = %d, retrying...\n", name, ret); msleep(CONNECTION_ATTEMPT_TIMEOUT); } tzdev_teec_error("Failed to connect to %s socket after %d retries\n", name, MAX_CONNECTION_ATTEMPTS); *result = tzdev_teec_error_to_tee_error(ret); return ret; } void tzdev_teec_disconnect(struct sock_desc *socket) { tz_iwsock_release(socket); } int tzdev_teec_send(struct sock_desc *socket, void *data, uint32_t size, int flags, uint32_t *result, uint32_t *origin) { int ret; *origin = TEEC_ORIGIN_COMMS; *result = TEEC_SUCCESS; ret = tz_iwsock_write(socket, data, size, flags); if (ret >= 0 && ret != size) ret = -EMSGSIZE; if (ret < 0) *result = tzdev_teec_error_to_tee_error(ret); return ret; } int tzdev_teec_recv(struct sock_desc *socket, void *data, uint32_t size, int flags, uint32_t *result, uint32_t *origin) { int ret; *origin = TEEC_ORIGIN_COMMS; *result = TEEC_SUCCESS; ret = tz_iwsock_read(socket, data, size, flags); if (ret > 0 && ret != size) ret = -EMSGSIZE; if (!ret) ret = -ECONNRESET; if (ret < 0) *result = tzdev_teec_error_to_tee_error(ret); return ret; } int tzdev_teec_send_then_recv(struct sock_desc *socket, void *send_data, uint32_t send_size, int send_flags, void *recv_data, uint32_t recv_size, int recv_flags, uint32_t *result, uint32_t *origin) { int ret; ret = tzdev_teec_send(socket, send_data, send_size, send_flags, result, origin); if (ret < 0) return ret; ret = tzdev_teec_recv(socket, recv_data, recv_size, recv_flags, result, origin); if (ret < 0) return ret; return 0; } int tzdev_teec_check_reply(struct cmd_reply *reply, uint32_t cmd, uint32_t serial, uint32_t *result, uint32_t *origin) { int ret; *origin = TEEC_ORIGIN_COMMS; *result = TEEC_SUCCESS; if (reply->base.cmd != cmd) { tzdev_teec_error("Received wrong reply = %u, expected = %u\n", reply->base.cmd, cmd); ret = -ECOMM; goto out; } if (reply->base.serial != serial) { tzdev_teec_error("Received wrong reply serial = %u, expected = %u\n", reply->base.serial, serial); ret = -ECOMM; goto out; } return 0; out: *result = tzdev_teec_error_to_tee_error(ret); return ret; } uint32_t tzdev_teec_error_to_tee_error(int error) { switch (error) { case -EINVAL: return TEEC_ERROR_BAD_PARAMETERS; case -ENOMEM: return TEEC_ERROR_OUT_OF_MEMORY; case -EPIPE: case -ENOTCONN: case -ECONNREFUSED: case -EMSGSIZE: case -ECOMM: return TEEC_ERROR_COMMUNICATION; case -ECONNRESET: return TEEC_ERROR_TARGET_DEAD; case -ECANCELED: return TEEC_ERROR_CANCEL; default: tzdev_teec_error("Unknown error code = %d\n", error); return TEEC_ERROR_GENERIC; } } void tzdev_teec_fixup_origin(uint32_t result, uint32_t *origin) { if (result == TEEC_ERROR_TARGET_DEAD) *origin = TEEC_ORIGIN_TEE; }