1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016-2017, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <mm/mobj.h> 8 #include <kernel/pseudo_ta.h> 9 #include <optee_rpc_cmd.h> 10 #include <pta_socket.h> 11 #include <string.h> 12 #include <tee/tee_fs_rpc.h> 13 14 static uint32_t get_instance_id(struct ts_session *sess) 15 { 16 return sess->ctx->ops->get_instance_id(sess->ctx); 17 } 18 19 static TEE_Result socket_open(uint32_t instance_id, uint32_t param_types, 20 TEE_Param params[TEE_NUM_PARAMS]) 21 { 22 struct mobj *mobj; 23 TEE_Result res; 24 void *va; 25 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 26 TEE_PARAM_TYPE_MEMREF_INPUT, 27 TEE_PARAM_TYPE_VALUE_INPUT, 28 TEE_PARAM_TYPE_VALUE_OUTPUT); 29 30 if (exp_pt != param_types) { 31 DMSG("got param_types 0x%x, expected 0x%x", 32 param_types, exp_pt); 33 return TEE_ERROR_BAD_PARAMETERS; 34 } 35 36 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET, 37 THREAD_SHM_TYPE_APPLICATION, 38 params[1].memref.size, &mobj); 39 if (!va) 40 return TEE_ERROR_OUT_OF_MEMORY; 41 42 memcpy(va, params[1].memref.buffer, params[1].memref.size); 43 44 struct thread_param tpm[4] = { 45 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_OPEN, 46 instance_id, 0), 47 [1] = THREAD_PARAM_VALUE(IN, 48 params[0].value.b, /* server port number */ 49 params[2].value.a, /* protocol */ 50 params[0].value.a /* ip version */), 51 [2] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size), 52 [3] = THREAD_PARAM_VALUE(OUT, 0, 0, 0), 53 }; 54 55 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 4, tpm); 56 if (res == TEE_SUCCESS) 57 params[3].value.a = tpm[3].u.value.a; 58 59 return res; 60 } 61 62 static TEE_Result socket_close(uint32_t instance_id, uint32_t param_types, 63 TEE_Param params[TEE_NUM_PARAMS]) 64 { 65 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 66 TEE_PARAM_TYPE_NONE, 67 TEE_PARAM_TYPE_NONE, 68 TEE_PARAM_TYPE_NONE); 69 70 if (exp_pt != param_types) { 71 DMSG("got param_types 0x%x, expected 0x%x", 72 param_types, exp_pt); 73 return TEE_ERROR_BAD_PARAMETERS; 74 } 75 76 struct thread_param tpm = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_CLOSE, 77 instance_id, 78 params[0].value.a); 79 80 return thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm); 81 } 82 83 static TEE_Result socket_send(uint32_t instance_id, uint32_t param_types, 84 TEE_Param params[TEE_NUM_PARAMS]) 85 { 86 struct mobj *mobj; 87 TEE_Result res; 88 void *va; 89 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 90 TEE_PARAM_TYPE_MEMREF_INPUT, 91 TEE_PARAM_TYPE_VALUE_OUTPUT, 92 TEE_PARAM_TYPE_NONE); 93 94 if (exp_pt != param_types) { 95 DMSG("got param_types 0x%x, expected 0x%x", 96 param_types, exp_pt); 97 return TEE_ERROR_BAD_PARAMETERS; 98 } 99 100 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET, 101 THREAD_SHM_TYPE_APPLICATION, 102 params[1].memref.size, &mobj); 103 if (!va) 104 return TEE_ERROR_OUT_OF_MEMORY; 105 106 memcpy(va, params[1].memref.buffer, params[1].memref.size); 107 108 struct thread_param tpm[3] = { 109 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_SEND, instance_id, 110 params[0].value.a /* handle */), 111 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, params[1].memref.size), 112 [2] = THREAD_PARAM_VALUE(INOUT, params[0].value.b, /* timeout */ 113 0, 0), 114 }; 115 116 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm); 117 params[2].value.a = tpm[2].u.value.b; /* transmitted bytes */ 118 119 return res; 120 } 121 122 static TEE_Result socket_recv(uint32_t instance_id, uint32_t param_types, 123 TEE_Param params[TEE_NUM_PARAMS]) 124 { 125 struct mobj *mobj; 126 TEE_Result res; 127 void *va; 128 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 129 TEE_PARAM_TYPE_MEMREF_OUTPUT, 130 TEE_PARAM_TYPE_NONE, 131 TEE_PARAM_TYPE_NONE); 132 133 if (exp_pt != param_types) { 134 DMSG("got param_types 0x%x, expected 0x%x", 135 param_types, exp_pt); 136 return TEE_ERROR_BAD_PARAMETERS; 137 } 138 139 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET, 140 THREAD_SHM_TYPE_APPLICATION, 141 params[1].memref.size, &mobj); 142 if (!va) 143 return TEE_ERROR_OUT_OF_MEMORY; 144 145 struct thread_param tpm[3] = { 146 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id, 147 params[0].value.a /* handle */), 148 [1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size), 149 [2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */, 150 0, 0), 151 }; 152 153 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm); 154 155 if (tpm[1].u.memref.size > params[1].memref.size) 156 return TEE_ERROR_GENERIC; 157 params[1].memref.size = tpm[1].u.memref.size; 158 if (params[1].memref.size) 159 memcpy(params[1].memref.buffer, va, params[1].memref.size); 160 161 return res; 162 } 163 164 static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types, 165 TEE_Param params[TEE_NUM_PARAMS]) 166 { 167 struct mobj *mobj; 168 TEE_Result res; 169 void *va; 170 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 171 TEE_PARAM_TYPE_MEMREF_INOUT, 172 TEE_PARAM_TYPE_NONE, 173 TEE_PARAM_TYPE_NONE); 174 175 if (exp_pt != param_types) { 176 DMSG("got param_types 0x%x, expected 0x%x", 177 param_types, exp_pt); 178 return TEE_ERROR_BAD_PARAMETERS; 179 } 180 181 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET, 182 THREAD_SHM_TYPE_APPLICATION, 183 params[1].memref.size, &mobj); 184 if (!va) 185 return TEE_ERROR_OUT_OF_MEMORY; 186 187 memcpy(va, params[1].memref.buffer, params[1].memref.size); 188 189 struct thread_param tpm[3] = { 190 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL, 191 instance_id, 192 params[0].value.a /* handle */), 193 [1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, 194 params[1].memref.size), 195 [2] = THREAD_PARAM_VALUE(IN, 196 params[0].value.b /* ioctl command */, 197 0, 0), 198 }; 199 200 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm); 201 if (tpm[1].u.memref.size <= params[1].memref.size) 202 memcpy(params[1].memref.buffer, va, tpm[1].u.memref.size); 203 204 params[1].memref.size = tpm[1].u.memref.size; 205 206 return res; 207 } 208 209 typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types, 210 TEE_Param params[TEE_NUM_PARAMS]); 211 212 static const ta_func ta_funcs[] = { 213 [PTA_SOCKET_OPEN] = socket_open, 214 [PTA_SOCKET_CLOSE] = socket_close, 215 [PTA_SOCKET_SEND] = socket_send, 216 [PTA_SOCKET_RECV] = socket_recv, 217 [PTA_SOCKET_IOCTL] = socket_ioctl, 218 }; 219 220 /* 221 * Trusted Application Entry Points 222 */ 223 224 static TEE_Result pta_socket_open_session(uint32_t param_types __unused, 225 TEE_Param pParams[TEE_NUM_PARAMS] __unused, 226 void **sess_ctx) 227 { 228 struct ts_session *s = ts_get_calling_session(); 229 230 /* Check that we're called from a TA */ 231 if (!s || !is_user_ta_ctx(s->ctx)) 232 return TEE_ERROR_ACCESS_DENIED; 233 234 *sess_ctx = (void *)(vaddr_t)get_instance_id(s); 235 236 return TEE_SUCCESS; 237 } 238 239 static void pta_socket_close_session(void *sess_ctx) 240 { 241 TEE_Result res; 242 struct thread_param tpm = { 243 .attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = { 244 .a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx, 245 }, 246 }; 247 248 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm); 249 if (res != TEE_SUCCESS) 250 DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res); 251 } 252 253 static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id, 254 uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS]) 255 { 256 if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id]) 257 return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params); 258 259 return TEE_ERROR_NOT_IMPLEMENTED; 260 } 261 262 pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket", 263 .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT, 264 .open_session_entry_point = pta_socket_open_session, 265 .close_session_entry_point = pta_socket_close_session, 266 .invoke_command_entry_point = pta_socket_invoke_command); 267