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