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