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 = NULL; 126 TEE_Result res = TEE_SUCCESS; 127 void *va = NULL; 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 if (params[1].memref.size) { 140 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET, 141 THREAD_SHM_TYPE_APPLICATION, 142 params[1].memref.size, &mobj); 143 if (!va) 144 return TEE_ERROR_OUT_OF_MEMORY; 145 } 146 147 struct thread_param tpm[3] = { 148 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_RECV, instance_id, 149 params[0].value.a /* handle */), 150 [1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, params[1].memref.size), 151 [2] = THREAD_PARAM_VALUE(IN, params[0].value.b /* timeout */, 152 0, 0), 153 }; 154 155 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm); 156 157 if (params[1].memref.size) 158 memcpy(params[1].memref.buffer, va, 159 MIN(params[1].memref.size, tpm[1].u.memref.size)); 160 params[1].memref.size = tpm[1].u.memref.size; 161 162 return res; 163 } 164 165 static TEE_Result socket_ioctl(uint32_t instance_id, uint32_t param_types, 166 TEE_Param params[TEE_NUM_PARAMS]) 167 { 168 struct mobj *mobj; 169 TEE_Result res; 170 void *va; 171 uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 172 TEE_PARAM_TYPE_MEMREF_INOUT, 173 TEE_PARAM_TYPE_NONE, 174 TEE_PARAM_TYPE_NONE); 175 176 if (exp_pt != param_types) { 177 DMSG("got param_types 0x%x, expected 0x%x", 178 param_types, exp_pt); 179 return TEE_ERROR_BAD_PARAMETERS; 180 } 181 182 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_SOCKET, 183 THREAD_SHM_TYPE_APPLICATION, 184 params[1].memref.size, &mobj); 185 if (!va) 186 return TEE_ERROR_OUT_OF_MEMORY; 187 188 memcpy(va, params[1].memref.buffer, params[1].memref.size); 189 190 struct thread_param tpm[3] = { 191 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SOCKET_IOCTL, 192 instance_id, 193 params[0].value.a /* handle */), 194 [1] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, 195 params[1].memref.size), 196 [2] = THREAD_PARAM_VALUE(IN, 197 params[0].value.b /* ioctl command */, 198 0, 0), 199 }; 200 201 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 3, tpm); 202 if (tpm[1].u.memref.size <= params[1].memref.size) 203 memcpy(params[1].memref.buffer, va, tpm[1].u.memref.size); 204 205 params[1].memref.size = tpm[1].u.memref.size; 206 207 return res; 208 } 209 210 typedef TEE_Result (*ta_func)(uint32_t instance_id, uint32_t param_types, 211 TEE_Param params[TEE_NUM_PARAMS]); 212 213 static const ta_func ta_funcs[] = { 214 [PTA_SOCKET_OPEN] = socket_open, 215 [PTA_SOCKET_CLOSE] = socket_close, 216 [PTA_SOCKET_SEND] = socket_send, 217 [PTA_SOCKET_RECV] = socket_recv, 218 [PTA_SOCKET_IOCTL] = socket_ioctl, 219 }; 220 221 /* 222 * Trusted Application Entry Points 223 */ 224 225 static TEE_Result pta_socket_open_session(uint32_t param_types __unused, 226 TEE_Param pParams[TEE_NUM_PARAMS] __unused, 227 void **sess_ctx) 228 { 229 struct ts_session *s = ts_get_calling_session(); 230 231 /* Check that we're called from a TA */ 232 if (!s || !is_user_ta_ctx(s->ctx)) 233 return TEE_ERROR_ACCESS_DENIED; 234 235 *sess_ctx = (void *)(vaddr_t)get_instance_id(s); 236 237 return TEE_SUCCESS; 238 } 239 240 static void pta_socket_close_session(void *sess_ctx) 241 { 242 TEE_Result res; 243 struct thread_param tpm = { 244 .attr = THREAD_PARAM_ATTR_VALUE_IN, .u.value = { 245 .a = OPTEE_RPC_SOCKET_CLOSE_ALL, .b = (vaddr_t)sess_ctx, 246 }, 247 }; 248 249 res = thread_rpc_cmd(OPTEE_RPC_CMD_SOCKET, 1, &tpm); 250 if (res != TEE_SUCCESS) 251 DMSG("OPTEE_RPC_SOCKET_CLOSE_ALL failed: %#" PRIx32, res); 252 } 253 254 static TEE_Result pta_socket_invoke_command(void *sess_ctx, uint32_t cmd_id, 255 uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS]) 256 { 257 if (cmd_id < ARRAY_SIZE(ta_funcs) && ta_funcs[cmd_id]) 258 return ta_funcs[cmd_id]((vaddr_t)sess_ctx, param_types, params); 259 260 return TEE_ERROR_NOT_IMPLEMENTED; 261 } 262 263 pseudo_ta_register(.uuid = PTA_SOCKET_UUID, .name = "socket", 264 .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT, 265 .open_session_entry_point = pta_socket_open_session, 266 .close_session_entry_point = pta_socket_close_session, 267 .invoke_command_entry_point = pta_socket_invoke_command); 268