16e9e277fSJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
26e9e277fSJerome Forissier /*
36e9e277fSJerome Forissier * Copyright (c) 2016-2017, Linaro Limited
46e9e277fSJerome Forissier */
56e9e277fSJerome Forissier
66e9e277fSJerome Forissier #include <assert.h>
76e9e277fSJerome Forissier #include <mm/mobj.h>
86e9e277fSJerome Forissier #include <kernel/pseudo_ta.h>
9*090e9463SJens Wiklander #include <kernel/user_access.h>
106e9e277fSJerome Forissier #include <optee_rpc_cmd.h>
116e9e277fSJerome Forissier #include <pta_socket.h>
126e9e277fSJerome Forissier #include <string.h>
136e9e277fSJerome Forissier #include <tee/tee_fs_rpc.h>
146e9e277fSJerome Forissier
get_instance_id(struct ts_session * sess)1500b3b9a2SJens Wiklander static uint32_t get_instance_id(struct ts_session *sess)
166e9e277fSJerome Forissier {
176e9e277fSJerome Forissier return sess->ctx->ops->get_instance_id(sess->ctx);
186e9e277fSJerome Forissier }
196e9e277fSJerome Forissier
socket_open(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])206e9e277fSJerome Forissier static TEE_Result socket_open(uint32_t instance_id, uint32_t param_types,
216e9e277fSJerome Forissier TEE_Param params[TEE_NUM_PARAMS])
226e9e277fSJerome Forissier {
237c94d5d6SJens Wiklander struct thread_param tpm[4] = { };
247c94d5d6SJens Wiklander struct mobj *mobj = NULL;
257c94d5d6SJens Wiklander TEE_Result res = TEE_SUCCESS;
267c94d5d6SJens Wiklander void *va = NULL;
276e9e277fSJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
286e9e277fSJerome Forissier TEE_PARAM_TYPE_MEMREF_INPUT,
296e9e277fSJerome Forissier TEE_PARAM_TYPE_VALUE_INPUT,
306e9e277fSJerome Forissier TEE_PARAM_TYPE_VALUE_OUTPUT);
316e9e277fSJerome Forissier
326e9e277fSJerome Forissier if (exp_pt != param_types) {
336e9e277fSJerome Forissier DMSG("got param_types 0x%x, expected 0x%x",
346e9e277fSJerome Forissier param_types, exp_pt);
356e9e277fSJerome Forissier return TEE_ERROR_BAD_PARAMETERS;
366e9e277fSJerome Forissier }
376e9e277fSJerome Forissier
381a7d8eaeSJens Wiklander va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
391a7d8eaeSJens Wiklander THREAD_SHM_TYPE_APPLICATION,
409bee8f2aSJens Wiklander params[1].memref.size, &mobj);
416e9e277fSJerome Forissier if (!va)
426e9e277fSJerome Forissier return TEE_ERROR_OUT_OF_MEMORY;
436e9e277fSJerome Forissier
44*090e9463SJens Wiklander res = copy_from_user(va, params[1].memref.buffer,
45*090e9463SJens Wiklander params[1].memref.size);
46*090e9463SJens Wiklander if (res)
47*090e9463SJens Wiklander return res;
486e9e277fSJerome Forissier
497c94d5d6SJens Wiklander tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN, instance_id, 0);
507c94d5d6SJens Wiklander tpm[1] = THREAD_PARAM_VALUE(IN,
516e9e277fSJerome Forissier params[0].value.b, /* server port number */
526e9e277fSJerome Forissier params[2].value.a, /* protocol */
537c94d5d6SJens Wiklander params[0].value.a /* ip version */);
547c94d5d6SJens Wiklander tpm[2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
557c94d5d6SJens Wiklander tpm[3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0);
566e9e277fSJerome Forissier
576e9e277fSJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 4, tpm);
586e9e277fSJerome Forissier if (res == TEE_SUCCESS)
596e9e277fSJerome Forissier params[3].value.a = tpm[3].u.value.a;
606e9e277fSJerome Forissier
616e9e277fSJerome Forissier return res;
626e9e277fSJerome Forissier }
636e9e277fSJerome Forissier
socket_close(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])646e9e277fSJerome Forissier static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types,
656e9e277fSJerome Forissier TEE_Param params[TEE_NUM_PARAMS])
666e9e277fSJerome Forissier {
677c94d5d6SJens Wiklander struct thread_param tpm = { };
686e9e277fSJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
696e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE,
706e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE,
716e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE);
726e9e277fSJerome Forissier
736e9e277fSJerome Forissier if (exp_pt != param_types) {
746e9e277fSJerome Forissier DMSG("got param_types 0x%x, expected 0x%x",
756e9e277fSJerome Forissier param_types, exp_pt);
766e9e277fSJerome Forissier return TEE_ERROR_BAD_PARAMETERS;
776e9e277fSJerome Forissier }
786e9e277fSJerome Forissier
797c94d5d6SJens Wiklander tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE, instance_id,
806e9e277fSJerome Forissier params[0].value.a);
816e9e277fSJerome Forissier
826e9e277fSJerome Forissier return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
836e9e277fSJerome Forissier }
846e9e277fSJerome Forissier
socket_send(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])856e9e277fSJerome Forissier static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types,
866e9e277fSJerome Forissier TEE_Param params[TEE_NUM_PARAMS])
876e9e277fSJerome Forissier {
887c94d5d6SJens Wiklander struct thread_param tpm[3] = { };
897c94d5d6SJens Wiklander struct mobj *mobj = NULL;
907c94d5d6SJens Wiklander TEE_Result res = TEE_SUCCESS;
917c94d5d6SJens Wiklander void *va = NULL;
926e9e277fSJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
936e9e277fSJerome Forissier TEE_PARAM_TYPE_MEMREF_INPUT,
946e9e277fSJerome Forissier TEE_PARAM_TYPE_VALUE_OUTPUT,
956e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE);
966e9e277fSJerome Forissier
976e9e277fSJerome Forissier if (exp_pt != param_types) {
986e9e277fSJerome Forissier DMSG("got param_types 0x%x, expected 0x%x",
996e9e277fSJerome Forissier param_types, exp_pt);
1006e9e277fSJerome Forissier return TEE_ERROR_BAD_PARAMETERS;
1016e9e277fSJerome Forissier }
1026e9e277fSJerome Forissier
1031a7d8eaeSJens Wiklander va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1041a7d8eaeSJens Wiklander THREAD_SHM_TYPE_APPLICATION,
1059bee8f2aSJens Wiklander params[1].memref.size, &mobj);
1066e9e277fSJerome Forissier if (!va)
1076e9e277fSJerome Forissier return TEE_ERROR_OUT_OF_MEMORY;
1086e9e277fSJerome Forissier
109*090e9463SJens Wiklander res = copy_from_user(va, params[1].memref.buffer,
110*090e9463SJens Wiklander params[1].memref.size);
111*090e9463SJens Wiklander if (res)
112*090e9463SJens Wiklander return res;
1136e9e277fSJerome Forissier
1147c94d5d6SJens Wiklander tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id,
1157c94d5d6SJens Wiklander params[0].value.a /* handle */);
1167c94d5d6SJens Wiklander tpm[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size);
1177c94d5d6SJens Wiklander tpm[2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */
1187c94d5d6SJens Wiklander 0, 0);
1196e9e277fSJerome Forissier
1206e9e277fSJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1216e9e277fSJerome Forissier params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */
1226e9e277fSJerome Forissier
1236e9e277fSJerome Forissier return res;
1246e9e277fSJerome Forissier }
1256e9e277fSJerome Forissier
socket_recv(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])1266e9e277fSJerome Forissier static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types,
1276e9e277fSJerome Forissier TEE_Param params[TEE_NUM_PARAMS])
1286e9e277fSJerome Forissier {
1297c94d5d6SJens Wiklander struct thread_param tpm[3] = { };
130e9907fd7SJens Wiklander struct mobj *mobj = NULL;
131e9907fd7SJens Wiklander TEE_Result res = TEE_SUCCESS;
132e9907fd7SJens Wiklander void *va = NULL;
1336e9e277fSJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1346e9e277fSJerome Forissier TEE_PARAM_TYPE_MEMREF_OUTPUT,
1356e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE,
1366e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE);
1376e9e277fSJerome Forissier
1386e9e277fSJerome Forissier if (exp_pt != param_types) {
1396e9e277fSJerome Forissier DMSG("got param_types 0x%x, expected 0x%x",
1406e9e277fSJerome Forissier param_types, exp_pt);
1416e9e277fSJerome Forissier return TEE_ERROR_BAD_PARAMETERS;
1426e9e277fSJerome Forissier }
1436e9e277fSJerome Forissier
144e9907fd7SJens Wiklander if (params[1].memref.size) {
1451a7d8eaeSJens Wiklander va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1461a7d8eaeSJens Wiklander THREAD_SHM_TYPE_APPLICATION,
1479bee8f2aSJens Wiklander params[1].memref.size, &mobj);
1486e9e277fSJerome Forissier if (!va)
1496e9e277fSJerome Forissier return TEE_ERROR_OUT_OF_MEMORY;
150e9907fd7SJens Wiklander }
1516e9e277fSJerome Forissier
1527c94d5d6SJens Wiklander tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id,
1537c94d5d6SJens Wiklander params[0].value.a /* handle */);
1547c94d5d6SJens Wiklander tpm[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size);
1557c94d5d6SJens Wiklander tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */, 0, 0);
1566e9e277fSJerome Forissier
1576e9e277fSJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
1586e9e277fSJerome Forissier
159*090e9463SJens Wiklander if (params[1].memref.size) {
160*090e9463SJens Wiklander TEE_Result res2 = TEE_SUCCESS;
161*090e9463SJens Wiklander
162*090e9463SJens Wiklander res2 = copy_to_user(params[1].memref.buffer, va,
163*090e9463SJens Wiklander MIN(params[1].memref.size,
164*090e9463SJens Wiklander tpm[1].u.memref.size));
165*090e9463SJens Wiklander if (res2)
166*090e9463SJens Wiklander return res2;
167*090e9463SJens Wiklander }
168e9907fd7SJens Wiklander params[1].memref.size = tpm[1].u.memref.size;
1696e9e277fSJerome Forissier
1706e9e277fSJerome Forissier return res;
1716e9e277fSJerome Forissier }
1726e9e277fSJerome Forissier
socket_ioctl(uint32_t instance_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])1736e9e277fSJerome Forissier static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types,
1746e9e277fSJerome Forissier TEE_Param params[TEE_NUM_PARAMS])
1756e9e277fSJerome Forissier {
1767c94d5d6SJens Wiklander struct thread_param tpm[3] = { };
1777c94d5d6SJens Wiklander struct mobj *mobj = NULL;
1787c94d5d6SJens Wiklander TEE_Result res = TEE_SUCCESS;
1797c94d5d6SJens Wiklander void *va = NULL;
1806e9e277fSJerome Forissier uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
1816e9e277fSJerome Forissier TEE_PARAM_TYPE_MEMREF_INOUT,
1826e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE,
1836e9e277fSJerome Forissier TEE_PARAM_TYPE_NONE);
1846e9e277fSJerome Forissier
1856e9e277fSJerome Forissier if (exp_pt != param_types) {
1866e9e277fSJerome Forissier DMSG("got param_types 0x%x, expected 0x%x",
1876e9e277fSJerome Forissier param_types, exp_pt);
1886e9e277fSJerome Forissier return TEE_ERROR_BAD_PARAMETERS;
1896e9e277fSJerome Forissier }
1906e9e277fSJerome Forissier
1911a7d8eaeSJens Wiklander va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET,
1921a7d8eaeSJens Wiklander THREAD_SHM_TYPE_APPLICATION,
1939bee8f2aSJens Wiklander params[1].memref.size, &mobj);
1946e9e277fSJerome Forissier if (!va)
1956e9e277fSJerome Forissier return TEE_ERROR_OUT_OF_MEMORY;
1966e9e277fSJerome Forissier
197*090e9463SJens Wiklander res = copy_from_user(va, params[1].memref.buffer,
198*090e9463SJens Wiklander params[1].memref.size);
199*090e9463SJens Wiklander if (res)
200*090e9463SJens Wiklander return res;
2016e9e277fSJerome Forissier
2027c94d5d6SJens Wiklander tpm[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL, instance_id,
2037c94d5d6SJens Wiklander params[0].value.a /* handle */);
2047c94d5d6SJens Wiklander tpm[1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, params[1].memref.size);
2057c94d5d6SJens Wiklander tpm[2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* ioctl command */,
2067c94d5d6SJens Wiklander 0, 0);
2076e9e277fSJerome Forissier
2086e9e277fSJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm);
209*090e9463SJens Wiklander if (tpm[1].u.memref.size <= params[1].memref.size) {
210*090e9463SJens Wiklander TEE_Result res2 = TEE_SUCCESS;
211*090e9463SJens Wiklander
212*090e9463SJens Wiklander res2 = copy_to_user(params[1].memref.buffer, va,
213*090e9463SJens Wiklander tpm[1].u.memref.size);
214*090e9463SJens Wiklander if (res2)
215*090e9463SJens Wiklander return res2;
216*090e9463SJens Wiklander }
2176e9e277fSJerome Forissier
2186e9e277fSJerome Forissier params[1].memref.size = tpm[1].u.memref.size;
2196e9e277fSJerome Forissier
2206e9e277fSJerome Forissier return res;
2216e9e277fSJerome Forissier }
2226e9e277fSJerome Forissier
2236e9e277fSJerome Forissier typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types,
2246e9e277fSJerome Forissier TEE_Param params[TEE_NUM_PARAMS]);
2256e9e277fSJerome Forissier
2266e9e277fSJerome Forissier static const ta_func ta_funcs[] = {
2276e9e277fSJerome Forissier [PTA_SOCKET_OPEN] = socket_open,
2286e9e277fSJerome Forissier [PTA_SOCKET_CLOSE] = socket_close,
2296e9e277fSJerome Forissier [PTA_SOCKET_SEND] = socket_send,
2306e9e277fSJerome Forissier [PTA_SOCKET_RECV] = socket_recv,
2316e9e277fSJerome Forissier [PTA_SOCKET_IOCTL] = socket_ioctl,
2326e9e277fSJerome Forissier };
2336e9e277fSJerome Forissier
2346e9e277fSJerome Forissier /*
2356e9e277fSJerome Forissier * Trusted Application Entry Points
2366e9e277fSJerome Forissier */
2376e9e277fSJerome Forissier
pta_socket_open_session(uint32_t param_types __unused,TEE_Param pParams[TEE_NUM_PARAMS]__unused,void ** sess_ctx)2386e9e277fSJerome Forissier static TEE_Result pta_socket_open_session(uint32_t param_types __unused,
2396e9e277fSJerome Forissier TEE_Param pParams[TEE_NUM_PARAMS] __unused,
2406e9e277fSJerome Forissier void **sess_ctx)
2416e9e277fSJerome Forissier {
24200b3b9a2SJens Wiklander struct ts_session *s = ts_get_calling_session();
2436e9e277fSJerome Forissier
2446e9e277fSJerome Forissier /* Check that we're called from a TA */
24500b3b9a2SJens Wiklander if (!s || !is_user_ta_ctx(s->ctx))
2466e9e277fSJerome Forissier return TEE_ERROR_ACCESS_DENIED;
2476e9e277fSJerome Forissier
2486e9e277fSJerome Forissier *sess_ctx = (void *)(vaddr_t)get_instance_id(s);
2496e9e277fSJerome Forissier
2506e9e277fSJerome Forissier return TEE_SUCCESS;
2516e9e277fSJerome Forissier }
2526e9e277fSJerome Forissier
pta_socket_close_session(void * sess_ctx)2536e9e277fSJerome Forissier static void pta_socket_close_session(void *sess_ctx)
2546e9e277fSJerome Forissier {
2556e9e277fSJerome Forissier TEE_Result res;
2566e9e277fSJerome Forissier struct thread_param tpm = {
2576e9e277fSJerome Forissier .attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = {
2586e9e277fSJerome Forissier .a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx,
2596e9e277fSJerome Forissier },
2606e9e277fSJerome Forissier };
2616e9e277fSJerome Forissier
2626e9e277fSJerome Forissier res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm);
2636e9e277fSJerome Forissier if (res != TEE_SUCCESS)
2646e9e277fSJerome Forissier DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res);
2656e9e277fSJerome Forissier }
2666e9e277fSJerome Forissier
pta_socket_invoke_command(void * sess_ctx,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])2676e9e277fSJerome Forissier static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id,
2686e9e277fSJerome Forissier uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS])
2696e9e277fSJerome Forissier {
2706e9e277fSJerome Forissier if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id])
2716e9e277fSJerome Forissier return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params);
2726e9e277fSJerome Forissier
2736e9e277fSJerome Forissier return TEE_ERROR_NOT_IMPLEMENTED;
2746e9e277fSJerome Forissier }
2756e9e277fSJerome Forissier
2766e9e277fSJerome Forissier pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket",
2776e9e277fSJerome Forissier .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
2786e9e277fSJerome Forissier .open_session_entry_point = pta_socket_open_session,
2796e9e277fSJerome Forissier .close_session_entry_point = pta_socket_close_session,
2806e9e277fSJerome Forissier .invoke_command_entry_point = pta_socket_invoke_command);
281