1*344aa361SAndroid Build Coastguard Worker /*
2*344aa361SAndroid Build Coastguard Worker * Copyright (c) 2013, Google, Inc. All rights reserved
3*344aa361SAndroid Build Coastguard Worker *
4*344aa361SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining
5*344aa361SAndroid Build Coastguard Worker * a copy of this software and associated documentation files
6*344aa361SAndroid Build Coastguard Worker * (the "Software"), to deal in the Software without restriction,
7*344aa361SAndroid Build Coastguard Worker * including without limitation the rights to use, copy, modify, merge,
8*344aa361SAndroid Build Coastguard Worker * publish, distribute, sublicense, and/or sell copies of the Software,
9*344aa361SAndroid Build Coastguard Worker * and to permit persons to whom the Software is furnished to do so,
10*344aa361SAndroid Build Coastguard Worker * subject to the following conditions:
11*344aa361SAndroid Build Coastguard Worker *
12*344aa361SAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be
13*344aa361SAndroid Build Coastguard Worker * included in all copies or substantial portions of the Software.
14*344aa361SAndroid Build Coastguard Worker *
15*344aa361SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*344aa361SAndroid Build Coastguard Worker * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*344aa361SAndroid Build Coastguard Worker * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18*344aa361SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19*344aa361SAndroid Build Coastguard Worker * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20*344aa361SAndroid Build Coastguard Worker * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21*344aa361SAndroid Build Coastguard Worker * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*344aa361SAndroid Build Coastguard Worker */
23*344aa361SAndroid Build Coastguard Worker
24*344aa361SAndroid Build Coastguard Worker #define LOCAL_TRACE 0
25*344aa361SAndroid Build Coastguard Worker
26*344aa361SAndroid Build Coastguard Worker #include <assert.h>
27*344aa361SAndroid Build Coastguard Worker #include <err.h>
28*344aa361SAndroid Build Coastguard Worker #include <kernel/usercopy.h>
29*344aa361SAndroid Build Coastguard Worker #include <list.h>
30*344aa361SAndroid Build Coastguard Worker #include <platform.h>
31*344aa361SAndroid Build Coastguard Worker #include <stdlib.h>
32*344aa361SAndroid Build Coastguard Worker #include <string.h>
33*344aa361SAndroid Build Coastguard Worker #include <trace.h>
34*344aa361SAndroid Build Coastguard Worker
35*344aa361SAndroid Build Coastguard Worker #include <kernel/event.h>
36*344aa361SAndroid Build Coastguard Worker #include <kernel/mutex.h>
37*344aa361SAndroid Build Coastguard Worker #include <lk/init.h>
38*344aa361SAndroid Build Coastguard Worker
39*344aa361SAndroid Build Coastguard Worker #include <lib/syscall.h>
40*344aa361SAndroid Build Coastguard Worker
41*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/uuid.h>
42*344aa361SAndroid Build Coastguard Worker
43*344aa361SAndroid Build Coastguard Worker #if WITH_TRUSTY_IPC
44*344aa361SAndroid Build Coastguard Worker
45*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/event.h>
46*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/ipc.h>
47*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/trusty_app.h>
48*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/uctx.h>
49*344aa361SAndroid Build Coastguard Worker
50*344aa361SAndroid Build Coastguard Worker #include <reflist.h>
51*344aa361SAndroid Build Coastguard Worker
52*344aa361SAndroid Build Coastguard Worker static struct list_node waiting_for_port_chan_list =
53*344aa361SAndroid Build Coastguard Worker LIST_INITIAL_VALUE(waiting_for_port_chan_list);
54*344aa361SAndroid Build Coastguard Worker
55*344aa361SAndroid Build Coastguard Worker static struct list_node ipc_port_list = LIST_INITIAL_VALUE(ipc_port_list);
56*344aa361SAndroid Build Coastguard Worker
57*344aa361SAndroid Build Coastguard Worker static struct mutex ipc_port_lock = MUTEX_INITIAL_VALUE(ipc_port_lock);
58*344aa361SAndroid Build Coastguard Worker
59*344aa361SAndroid Build Coastguard Worker static uint32_t port_poll(struct handle* handle, uint32_t emask, bool finalize);
60*344aa361SAndroid Build Coastguard Worker static void port_shutdown(struct handle* handle);
61*344aa361SAndroid Build Coastguard Worker static void port_handle_destroy(struct handle* handle);
62*344aa361SAndroid Build Coastguard Worker
63*344aa361SAndroid Build Coastguard Worker static uint32_t chan_poll(struct handle* handle, uint32_t emask, bool finalize);
64*344aa361SAndroid Build Coastguard Worker static void chan_handle_destroy(struct handle* handle);
65*344aa361SAndroid Build Coastguard Worker
66*344aa361SAndroid Build Coastguard Worker static struct ipc_port* port_find_locked(const char* path);
67*344aa361SAndroid Build Coastguard Worker static int port_attach_client(struct ipc_port* port, struct ipc_chan* client);
68*344aa361SAndroid Build Coastguard Worker static void chan_shutdown(struct ipc_chan* chan);
69*344aa361SAndroid Build Coastguard Worker static void chan_add_ref(struct ipc_chan* conn, struct obj_ref* ref);
70*344aa361SAndroid Build Coastguard Worker static void chan_del_ref(struct ipc_chan* conn, struct obj_ref* ref);
71*344aa361SAndroid Build Coastguard Worker
72*344aa361SAndroid Build Coastguard Worker static void remove_from_waiting_for_port_list_locked(struct ipc_chan* client,
73*344aa361SAndroid Build Coastguard Worker struct obj_ref* ref);
74*344aa361SAndroid Build Coastguard Worker
75*344aa361SAndroid Build Coastguard Worker static struct handle_ops ipc_port_handle_ops = {
76*344aa361SAndroid Build Coastguard Worker .poll = port_poll,
77*344aa361SAndroid Build Coastguard Worker .destroy = port_handle_destroy,
78*344aa361SAndroid Build Coastguard Worker };
79*344aa361SAndroid Build Coastguard Worker
80*344aa361SAndroid Build Coastguard Worker static struct handle_ops ipc_chan_handle_ops = {
81*344aa361SAndroid Build Coastguard Worker .poll = chan_poll,
82*344aa361SAndroid Build Coastguard Worker .destroy = chan_handle_destroy,
83*344aa361SAndroid Build Coastguard Worker };
84*344aa361SAndroid Build Coastguard Worker
ipc_is_channel(struct handle * handle)85*344aa361SAndroid Build Coastguard Worker bool ipc_is_channel(struct handle* handle) {
86*344aa361SAndroid Build Coastguard Worker return likely(handle->ops == &ipc_chan_handle_ops);
87*344aa361SAndroid Build Coastguard Worker }
88*344aa361SAndroid Build Coastguard Worker
ipc_is_port(struct handle * handle)89*344aa361SAndroid Build Coastguard Worker bool ipc_is_port(struct handle* handle) {
90*344aa361SAndroid Build Coastguard Worker return likely(handle->ops == &ipc_port_handle_ops);
91*344aa361SAndroid Build Coastguard Worker }
92*344aa361SAndroid Build Coastguard Worker
ipc_connection_waiting_for_port(const char * path,uint32_t flags)93*344aa361SAndroid Build Coastguard Worker bool ipc_connection_waiting_for_port(const char* path, uint32_t flags) {
94*344aa361SAndroid Build Coastguard Worker bool found = false;
95*344aa361SAndroid Build Coastguard Worker struct ipc_chan* chan;
96*344aa361SAndroid Build Coastguard Worker
97*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
98*344aa361SAndroid Build Coastguard Worker list_for_every_entry(&waiting_for_port_chan_list, chan, struct ipc_chan,
99*344aa361SAndroid Build Coastguard Worker node) {
100*344aa361SAndroid Build Coastguard Worker if (!strncmp(path, chan->path, IPC_PORT_PATH_MAX) &&
101*344aa361SAndroid Build Coastguard Worker ipc_port_check_access(flags, chan->uuid) == NO_ERROR) {
102*344aa361SAndroid Build Coastguard Worker found = true;
103*344aa361SAndroid Build Coastguard Worker break;
104*344aa361SAndroid Build Coastguard Worker }
105*344aa361SAndroid Build Coastguard Worker }
106*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
107*344aa361SAndroid Build Coastguard Worker
108*344aa361SAndroid Build Coastguard Worker return found;
109*344aa361SAndroid Build Coastguard Worker }
110*344aa361SAndroid Build Coastguard Worker
ipc_remove_connection_waiting_for_port(const char * path,uint32_t flags)111*344aa361SAndroid Build Coastguard Worker void ipc_remove_connection_waiting_for_port(const char* path, uint32_t flags) {
112*344aa361SAndroid Build Coastguard Worker struct ipc_chan *chan, *temp;
113*344aa361SAndroid Build Coastguard Worker struct obj_ref tmp_chan_ref = OBJ_REF_INITIAL_VALUE(tmp_chan_ref);
114*344aa361SAndroid Build Coastguard Worker
115*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
116*344aa361SAndroid Build Coastguard Worker list_for_every_entry_safe(&waiting_for_port_chan_list, chan, temp,
117*344aa361SAndroid Build Coastguard Worker struct ipc_chan, node) {
118*344aa361SAndroid Build Coastguard Worker if (!strncmp(path, chan->path, IPC_PORT_PATH_MAX) &&
119*344aa361SAndroid Build Coastguard Worker ipc_port_check_access(flags, chan->uuid) == NO_ERROR) {
120*344aa361SAndroid Build Coastguard Worker remove_from_waiting_for_port_list_locked(chan, &tmp_chan_ref);
121*344aa361SAndroid Build Coastguard Worker chan_shutdown(chan);
122*344aa361SAndroid Build Coastguard Worker chan_del_ref(chan, &tmp_chan_ref); /* drop local ref */
123*344aa361SAndroid Build Coastguard Worker }
124*344aa361SAndroid Build Coastguard Worker }
125*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
126*344aa361SAndroid Build Coastguard Worker }
127*344aa361SAndroid Build Coastguard Worker
128*344aa361SAndroid Build Coastguard Worker /*
129*344aa361SAndroid Build Coastguard Worker * Called by user task to create a new port at the given path.
130*344aa361SAndroid Build Coastguard Worker * The returned handle will be later installed into uctx.
131*344aa361SAndroid Build Coastguard Worker */
ipc_port_create(const uuid_t * sid,const char * path,uint num_recv_bufs,size_t recv_buf_size,uint32_t flags,struct handle ** phandle_ptr)132*344aa361SAndroid Build Coastguard Worker int ipc_port_create(const uuid_t* sid,
133*344aa361SAndroid Build Coastguard Worker const char* path,
134*344aa361SAndroid Build Coastguard Worker uint num_recv_bufs,
135*344aa361SAndroid Build Coastguard Worker size_t recv_buf_size,
136*344aa361SAndroid Build Coastguard Worker uint32_t flags,
137*344aa361SAndroid Build Coastguard Worker struct handle** phandle_ptr) {
138*344aa361SAndroid Build Coastguard Worker struct ipc_port* new_port;
139*344aa361SAndroid Build Coastguard Worker int ret = 0;
140*344aa361SAndroid Build Coastguard Worker
141*344aa361SAndroid Build Coastguard Worker LTRACEF("creating port (%s)\n", path);
142*344aa361SAndroid Build Coastguard Worker
143*344aa361SAndroid Build Coastguard Worker if (!sid) {
144*344aa361SAndroid Build Coastguard Worker /* server uuid is required */
145*344aa361SAndroid Build Coastguard Worker LTRACEF("server uuid is required\n");
146*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
147*344aa361SAndroid Build Coastguard Worker }
148*344aa361SAndroid Build Coastguard Worker
149*344aa361SAndroid Build Coastguard Worker if (!num_recv_bufs || num_recv_bufs > IPC_CHAN_MAX_BUFS || !recv_buf_size ||
150*344aa361SAndroid Build Coastguard Worker recv_buf_size > IPC_CHAN_MAX_BUF_SIZE) {
151*344aa361SAndroid Build Coastguard Worker LTRACEF("Invalid buffer sizes: %d x %zd\n", num_recv_bufs,
152*344aa361SAndroid Build Coastguard Worker recv_buf_size);
153*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
154*344aa361SAndroid Build Coastguard Worker }
155*344aa361SAndroid Build Coastguard Worker
156*344aa361SAndroid Build Coastguard Worker new_port = calloc(1, sizeof(struct ipc_port));
157*344aa361SAndroid Build Coastguard Worker if (!new_port) {
158*344aa361SAndroid Build Coastguard Worker LTRACEF("cannot allocate memory for port\n");
159*344aa361SAndroid Build Coastguard Worker return ERR_NO_MEMORY;
160*344aa361SAndroid Build Coastguard Worker }
161*344aa361SAndroid Build Coastguard Worker
162*344aa361SAndroid Build Coastguard Worker ret = strlcpy(new_port->path, path, sizeof(new_port->path));
163*344aa361SAndroid Build Coastguard Worker if (ret == 0) {
164*344aa361SAndroid Build Coastguard Worker LTRACEF("path is empty\n");
165*344aa361SAndroid Build Coastguard Worker ret = ERR_INVALID_ARGS;
166*344aa361SAndroid Build Coastguard Worker goto err_copy_path;
167*344aa361SAndroid Build Coastguard Worker }
168*344aa361SAndroid Build Coastguard Worker
169*344aa361SAndroid Build Coastguard Worker if ((uint)ret >= sizeof(new_port->path)) {
170*344aa361SAndroid Build Coastguard Worker LTRACEF("path is too long (%d)\n", ret);
171*344aa361SAndroid Build Coastguard Worker ret = ERR_TOO_BIG;
172*344aa361SAndroid Build Coastguard Worker goto err_copy_path;
173*344aa361SAndroid Build Coastguard Worker }
174*344aa361SAndroid Build Coastguard Worker
175*344aa361SAndroid Build Coastguard Worker new_port->uuid = sid;
176*344aa361SAndroid Build Coastguard Worker new_port->num_recv_bufs = num_recv_bufs;
177*344aa361SAndroid Build Coastguard Worker new_port->recv_buf_size = recv_buf_size;
178*344aa361SAndroid Build Coastguard Worker new_port->flags = flags;
179*344aa361SAndroid Build Coastguard Worker
180*344aa361SAndroid Build Coastguard Worker new_port->state = IPC_PORT_STATE_INVALID;
181*344aa361SAndroid Build Coastguard Worker list_initialize(&new_port->pending_list);
182*344aa361SAndroid Build Coastguard Worker
183*344aa361SAndroid Build Coastguard Worker handle_init(&new_port->handle, &ipc_port_handle_ops);
184*344aa361SAndroid Build Coastguard Worker
185*344aa361SAndroid Build Coastguard Worker LTRACEF("new port %p created (%s)\n", new_port, new_port->path);
186*344aa361SAndroid Build Coastguard Worker
187*344aa361SAndroid Build Coastguard Worker *phandle_ptr = &new_port->handle;
188*344aa361SAndroid Build Coastguard Worker
189*344aa361SAndroid Build Coastguard Worker return NO_ERROR;
190*344aa361SAndroid Build Coastguard Worker
191*344aa361SAndroid Build Coastguard Worker err_copy_path:
192*344aa361SAndroid Build Coastguard Worker free(new_port);
193*344aa361SAndroid Build Coastguard Worker return ret;
194*344aa361SAndroid Build Coastguard Worker }
195*344aa361SAndroid Build Coastguard Worker
196*344aa361SAndroid Build Coastguard Worker #if TEST_BUILD
ipc_get_port_list(struct ipc_port ** out_port_list)197*344aa361SAndroid Build Coastguard Worker int ipc_get_port_list(struct ipc_port** out_port_list) {
198*344aa361SAndroid Build Coastguard Worker struct ipc_port* port;
199*344aa361SAndroid Build Coastguard Worker
200*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
201*344aa361SAndroid Build Coastguard Worker int len = list_length(&ipc_port_list);
202*344aa361SAndroid Build Coastguard Worker *out_port_list = calloc(sizeof(struct ipc_port), len);
203*344aa361SAndroid Build Coastguard Worker if (out_port_list == NULL) {
204*344aa361SAndroid Build Coastguard Worker return ERR_NO_MEMORY;
205*344aa361SAndroid Build Coastguard Worker }
206*344aa361SAndroid Build Coastguard Worker struct ipc_port* current_port = *out_port_list;
207*344aa361SAndroid Build Coastguard Worker list_for_every_entry(&ipc_port_list, port, struct ipc_port, node) {
208*344aa361SAndroid Build Coastguard Worker memcpy(current_port, port, sizeof(struct ipc_port));
209*344aa361SAndroid Build Coastguard Worker ++current_port;
210*344aa361SAndroid Build Coastguard Worker }
211*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
212*344aa361SAndroid Build Coastguard Worker return len;
213*344aa361SAndroid Build Coastguard Worker }
214*344aa361SAndroid Build Coastguard Worker
ipc_free_port_list(struct ipc_port * out_port_list)215*344aa361SAndroid Build Coastguard Worker void ipc_free_port_list(struct ipc_port* out_port_list) {
216*344aa361SAndroid Build Coastguard Worker free(out_port_list);
217*344aa361SAndroid Build Coastguard Worker }
218*344aa361SAndroid Build Coastguard Worker #endif
219*344aa361SAndroid Build Coastguard Worker
add_to_waiting_for_port_list_locked(struct ipc_chan * client)220*344aa361SAndroid Build Coastguard Worker static void add_to_waiting_for_port_list_locked(struct ipc_chan* client) {
221*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(client);
222*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(!list_in_list(&client->node));
223*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(client->path);
224*344aa361SAndroid Build Coastguard Worker
225*344aa361SAndroid Build Coastguard Worker list_add_tail(&waiting_for_port_chan_list, &client->node);
226*344aa361SAndroid Build Coastguard Worker chan_add_ref(client, &client->node_ref);
227*344aa361SAndroid Build Coastguard Worker }
228*344aa361SAndroid Build Coastguard Worker
remove_from_waiting_for_port_list_locked(struct ipc_chan * client,struct obj_ref * ref)229*344aa361SAndroid Build Coastguard Worker static void remove_from_waiting_for_port_list_locked(struct ipc_chan* client,
230*344aa361SAndroid Build Coastguard Worker struct obj_ref* ref) {
231*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(client);
232*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(list_in_list(&client->node));
233*344aa361SAndroid Build Coastguard Worker
234*344aa361SAndroid Build Coastguard Worker free((void*)client->path);
235*344aa361SAndroid Build Coastguard Worker client->path = NULL;
236*344aa361SAndroid Build Coastguard Worker
237*344aa361SAndroid Build Coastguard Worker /* take it out of global pending list */
238*344aa361SAndroid Build Coastguard Worker chan_add_ref(client, ref); /* add local ref */
239*344aa361SAndroid Build Coastguard Worker list_delete(&client->node);
240*344aa361SAndroid Build Coastguard Worker chan_del_ref(client, &client->node_ref); /* drop list ref */
241*344aa361SAndroid Build Coastguard Worker }
242*344aa361SAndroid Build Coastguard Worker
243*344aa361SAndroid Build Coastguard Worker /*
244*344aa361SAndroid Build Coastguard Worker * Shutting down port
245*344aa361SAndroid Build Coastguard Worker *
246*344aa361SAndroid Build Coastguard Worker * Called by controlling handle gets closed.
247*344aa361SAndroid Build Coastguard Worker */
port_shutdown(struct handle * phandle)248*344aa361SAndroid Build Coastguard Worker static void port_shutdown(struct handle* phandle) {
249*344aa361SAndroid Build Coastguard Worker bool is_startup_port = false;
250*344aa361SAndroid Build Coastguard Worker struct ipc_chan* client;
251*344aa361SAndroid Build Coastguard Worker ASSERT(phandle);
252*344aa361SAndroid Build Coastguard Worker ASSERT(ipc_is_port(phandle));
253*344aa361SAndroid Build Coastguard Worker
254*344aa361SAndroid Build Coastguard Worker struct ipc_port* port = containerof(phandle, struct ipc_port, handle);
255*344aa361SAndroid Build Coastguard Worker
256*344aa361SAndroid Build Coastguard Worker LTRACEF("shutting down port %p\n", port);
257*344aa361SAndroid Build Coastguard Worker
258*344aa361SAndroid Build Coastguard Worker /* detach it from global list if it is in the list */
259*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
260*344aa361SAndroid Build Coastguard Worker if (list_in_list(&port->node)) {
261*344aa361SAndroid Build Coastguard Worker list_delete(&port->node);
262*344aa361SAndroid Build Coastguard Worker }
263*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
264*344aa361SAndroid Build Coastguard Worker
265*344aa361SAndroid Build Coastguard Worker is_startup_port = trusty_app_is_startup_port(port->path);
266*344aa361SAndroid Build Coastguard Worker
267*344aa361SAndroid Build Coastguard Worker /* tear down pending connections */
268*344aa361SAndroid Build Coastguard Worker struct ipc_chan *server, *temp;
269*344aa361SAndroid Build Coastguard Worker list_for_every_entry_safe(&port->pending_list, server, temp,
270*344aa361SAndroid Build Coastguard Worker struct ipc_chan, node) {
271*344aa361SAndroid Build Coastguard Worker /* Check if the port being shutdown has been registered by an
272*344aa361SAndroid Build Coastguard Worker * application. If so, detach the client connection and put it
273*344aa361SAndroid Build Coastguard Worker * back in the waiting for port list
274*344aa361SAndroid Build Coastguard Worker */
275*344aa361SAndroid Build Coastguard Worker if (is_startup_port) {
276*344aa361SAndroid Build Coastguard Worker bool client_connecting = false;
277*344aa361SAndroid Build Coastguard Worker /* Get a local ref to the client*/
278*344aa361SAndroid Build Coastguard Worker struct obj_ref tmp_client_ref =
279*344aa361SAndroid Build Coastguard Worker OBJ_REF_INITIAL_VALUE(tmp_client_ref);
280*344aa361SAndroid Build Coastguard Worker chan_add_ref(server->peer, &tmp_client_ref);
281*344aa361SAndroid Build Coastguard Worker
282*344aa361SAndroid Build Coastguard Worker /* Remove server -> client ref */
283*344aa361SAndroid Build Coastguard Worker client = server->peer;
284*344aa361SAndroid Build Coastguard Worker server->peer = NULL;
285*344aa361SAndroid Build Coastguard Worker chan_del_ref(client, &server->peer_ref);
286*344aa361SAndroid Build Coastguard Worker
287*344aa361SAndroid Build Coastguard Worker mutex_acquire(&client->mlock);
288*344aa361SAndroid Build Coastguard Worker if (client->state != IPC_CHAN_STATE_DISCONNECTING) {
289*344aa361SAndroid Build Coastguard Worker /*
290*344aa361SAndroid Build Coastguard Worker * Remove client -> server ref if the client hasn't been closed
291*344aa361SAndroid Build Coastguard Worker */
292*344aa361SAndroid Build Coastguard Worker client->peer = NULL;
293*344aa361SAndroid Build Coastguard Worker chan_del_ref(server, &client->peer_ref);
294*344aa361SAndroid Build Coastguard Worker ASSERT(client->state == IPC_CHAN_STATE_CONNECTING);
295*344aa361SAndroid Build Coastguard Worker client_connecting = true;
296*344aa361SAndroid Build Coastguard Worker }
297*344aa361SAndroid Build Coastguard Worker mutex_release(&client->mlock);
298*344aa361SAndroid Build Coastguard Worker
299*344aa361SAndroid Build Coastguard Worker if (client_connecting) {
300*344aa361SAndroid Build Coastguard Worker /*
301*344aa361SAndroid Build Coastguard Worker * Reset client. This is needed before adding the client back
302*344aa361SAndroid Build Coastguard Worker * to the waiting for port list but it is still safe to do if
303*344aa361SAndroid Build Coastguard Worker * the client changes to disconnecting since we still hold a
304*344aa361SAndroid Build Coastguard Worker * reference to the client. When all the references go away
305*344aa361SAndroid Build Coastguard Worker * the destructor checks if the msg_queue has already been
306*344aa361SAndroid Build Coastguard Worker * destroyed.
307*344aa361SAndroid Build Coastguard Worker */
308*344aa361SAndroid Build Coastguard Worker ipc_msg_queue_destroy(client->msg_queue);
309*344aa361SAndroid Build Coastguard Worker client->msg_queue = NULL;
310*344aa361SAndroid Build Coastguard Worker client->path = strdup(port->path);
311*344aa361SAndroid Build Coastguard Worker ASSERT(client->path);
312*344aa361SAndroid Build Coastguard Worker
313*344aa361SAndroid Build Coastguard Worker /* Add client to waiting_for_port list */
314*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
315*344aa361SAndroid Build Coastguard Worker if (client->state == IPC_CHAN_STATE_CONNECTING)
316*344aa361SAndroid Build Coastguard Worker add_to_waiting_for_port_list_locked(client);
317*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
318*344aa361SAndroid Build Coastguard Worker }
319*344aa361SAndroid Build Coastguard Worker
320*344aa361SAndroid Build Coastguard Worker /* Drop local ref */
321*344aa361SAndroid Build Coastguard Worker chan_del_ref(client, &tmp_client_ref);
322*344aa361SAndroid Build Coastguard Worker }
323*344aa361SAndroid Build Coastguard Worker
324*344aa361SAndroid Build Coastguard Worker /* remove connection from the list */
325*344aa361SAndroid Build Coastguard Worker mutex_acquire(&server->mlock);
326*344aa361SAndroid Build Coastguard Worker list_delete(&server->node);
327*344aa361SAndroid Build Coastguard Worker chan_del_ref(server, &server->node_ref); /* drop list ref */
328*344aa361SAndroid Build Coastguard Worker mutex_release(&server->mlock);
329*344aa361SAndroid Build Coastguard Worker
330*344aa361SAndroid Build Coastguard Worker /* pending server channel in not in user context table
331*344aa361SAndroid Build Coastguard Worker * but we need to decrement ref to get rid of it
332*344aa361SAndroid Build Coastguard Worker */
333*344aa361SAndroid Build Coastguard Worker handle_decref(&server->handle);
334*344aa361SAndroid Build Coastguard Worker }
335*344aa361SAndroid Build Coastguard Worker }
336*344aa361SAndroid Build Coastguard Worker
337*344aa361SAndroid Build Coastguard Worker /*
338*344aa361SAndroid Build Coastguard Worker * Destroy port controlled by handle
339*344aa361SAndroid Build Coastguard Worker *
340*344aa361SAndroid Build Coastguard Worker * Called when controlling handle refcount reaches 0.
341*344aa361SAndroid Build Coastguard Worker */
port_handle_destroy(struct handle * phandle)342*344aa361SAndroid Build Coastguard Worker static void port_handle_destroy(struct handle* phandle) {
343*344aa361SAndroid Build Coastguard Worker ASSERT(phandle);
344*344aa361SAndroid Build Coastguard Worker ASSERT(ipc_is_port(phandle));
345*344aa361SAndroid Build Coastguard Worker
346*344aa361SAndroid Build Coastguard Worker /* invoke port shutdown first */
347*344aa361SAndroid Build Coastguard Worker port_shutdown(phandle);
348*344aa361SAndroid Build Coastguard Worker
349*344aa361SAndroid Build Coastguard Worker struct ipc_port* port = containerof(phandle, struct ipc_port, handle);
350*344aa361SAndroid Build Coastguard Worker
351*344aa361SAndroid Build Coastguard Worker /* pending list should be empty and
352*344aa361SAndroid Build Coastguard Worker node should not be in the list
353*344aa361SAndroid Build Coastguard Worker */
354*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(list_is_empty(&port->pending_list));
355*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(!list_in_list(&port->node));
356*344aa361SAndroid Build Coastguard Worker
357*344aa361SAndroid Build Coastguard Worker LTRACEF("destroying port %p ('%s')\n", port, port->path);
358*344aa361SAndroid Build Coastguard Worker
359*344aa361SAndroid Build Coastguard Worker free(port);
360*344aa361SAndroid Build Coastguard Worker }
361*344aa361SAndroid Build Coastguard Worker
362*344aa361SAndroid Build Coastguard Worker /*
363*344aa361SAndroid Build Coastguard Worker * Make specified port publically available for operation.
364*344aa361SAndroid Build Coastguard Worker */
ipc_port_publish(struct handle * phandle)365*344aa361SAndroid Build Coastguard Worker int ipc_port_publish(struct handle* phandle) {
366*344aa361SAndroid Build Coastguard Worker int ret = NO_ERROR;
367*344aa361SAndroid Build Coastguard Worker
368*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(phandle);
369*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(ipc_is_port(phandle));
370*344aa361SAndroid Build Coastguard Worker
371*344aa361SAndroid Build Coastguard Worker struct ipc_port* port = containerof(phandle, struct ipc_port, handle);
372*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(!list_in_list(&port->node));
373*344aa361SAndroid Build Coastguard Worker
374*344aa361SAndroid Build Coastguard Worker /* Check for duplicates */
375*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
376*344aa361SAndroid Build Coastguard Worker if (port_find_locked(port->path)) {
377*344aa361SAndroid Build Coastguard Worker LTRACEF("path already exists\n");
378*344aa361SAndroid Build Coastguard Worker ret = ERR_ALREADY_EXISTS;
379*344aa361SAndroid Build Coastguard Worker } else {
380*344aa361SAndroid Build Coastguard Worker port->state = IPC_PORT_STATE_LISTENING;
381*344aa361SAndroid Build Coastguard Worker list_add_tail(&ipc_port_list, &port->node);
382*344aa361SAndroid Build Coastguard Worker
383*344aa361SAndroid Build Coastguard Worker /* go through pending connection list and pick those we can handle */
384*344aa361SAndroid Build Coastguard Worker struct ipc_chan *client, *temp;
385*344aa361SAndroid Build Coastguard Worker struct obj_ref tmp_client_ref = OBJ_REF_INITIAL_VALUE(tmp_client_ref);
386*344aa361SAndroid Build Coastguard Worker list_for_every_entry_safe(&waiting_for_port_chan_list, client, temp,
387*344aa361SAndroid Build Coastguard Worker struct ipc_chan, node) {
388*344aa361SAndroid Build Coastguard Worker if (strcmp(client->path, port->path))
389*344aa361SAndroid Build Coastguard Worker continue;
390*344aa361SAndroid Build Coastguard Worker
391*344aa361SAndroid Build Coastguard Worker remove_from_waiting_for_port_list_locked(client, &tmp_client_ref);
392*344aa361SAndroid Build Coastguard Worker
393*344aa361SAndroid Build Coastguard Worker /* try to attach port */
394*344aa361SAndroid Build Coastguard Worker int err = port_attach_client(port, client);
395*344aa361SAndroid Build Coastguard Worker if (err) {
396*344aa361SAndroid Build Coastguard Worker /* failed to attach port: close channel */
397*344aa361SAndroid Build Coastguard Worker LTRACEF("failed (%d) to attach_port\n", err);
398*344aa361SAndroid Build Coastguard Worker chan_shutdown(client);
399*344aa361SAndroid Build Coastguard Worker }
400*344aa361SAndroid Build Coastguard Worker
401*344aa361SAndroid Build Coastguard Worker chan_del_ref(client, &tmp_client_ref); /* drop local ref */
402*344aa361SAndroid Build Coastguard Worker }
403*344aa361SAndroid Build Coastguard Worker }
404*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
405*344aa361SAndroid Build Coastguard Worker
406*344aa361SAndroid Build Coastguard Worker return ret;
407*344aa361SAndroid Build Coastguard Worker }
408*344aa361SAndroid Build Coastguard Worker
409*344aa361SAndroid Build Coastguard Worker /*
410*344aa361SAndroid Build Coastguard Worker * Called by user task to create new port.
411*344aa361SAndroid Build Coastguard Worker *
412*344aa361SAndroid Build Coastguard Worker * On success - returns handle id (small integer) for the new port.
413*344aa361SAndroid Build Coastguard Worker * On error - returns negative error code.
414*344aa361SAndroid Build Coastguard Worker */
sys_port_create(user_addr_t path,uint32_t num_recv_bufs,uint32_t recv_buf_size,uint32_t flags)415*344aa361SAndroid Build Coastguard Worker long __SYSCALL sys_port_create(user_addr_t path,
416*344aa361SAndroid Build Coastguard Worker uint32_t num_recv_bufs,
417*344aa361SAndroid Build Coastguard Worker uint32_t recv_buf_size,
418*344aa361SAndroid Build Coastguard Worker uint32_t flags) {
419*344aa361SAndroid Build Coastguard Worker struct trusty_app* tapp = current_trusty_app();
420*344aa361SAndroid Build Coastguard Worker struct uctx* ctx = current_uctx();
421*344aa361SAndroid Build Coastguard Worker struct handle* port_handle = NULL;
422*344aa361SAndroid Build Coastguard Worker int ret;
423*344aa361SAndroid Build Coastguard Worker handle_id_t handle_id;
424*344aa361SAndroid Build Coastguard Worker char tmp_path[IPC_PORT_PATH_MAX];
425*344aa361SAndroid Build Coastguard Worker
426*344aa361SAndroid Build Coastguard Worker /* copy path from user space */
427*344aa361SAndroid Build Coastguard Worker ret = (int)strlcpy_from_user(tmp_path, path, sizeof(tmp_path));
428*344aa361SAndroid Build Coastguard Worker if (ret < 0)
429*344aa361SAndroid Build Coastguard Worker return (long)ret;
430*344aa361SAndroid Build Coastguard Worker
431*344aa361SAndroid Build Coastguard Worker if ((uint)ret >= sizeof(tmp_path)) {
432*344aa361SAndroid Build Coastguard Worker /* string is too long */
433*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
434*344aa361SAndroid Build Coastguard Worker }
435*344aa361SAndroid Build Coastguard Worker
436*344aa361SAndroid Build Coastguard Worker /* create new port */
437*344aa361SAndroid Build Coastguard Worker ret = ipc_port_create(&tapp->props.uuid, tmp_path, (uint)num_recv_bufs,
438*344aa361SAndroid Build Coastguard Worker recv_buf_size, flags, &port_handle);
439*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
440*344aa361SAndroid Build Coastguard Worker goto err_port_create;
441*344aa361SAndroid Build Coastguard Worker
442*344aa361SAndroid Build Coastguard Worker /* install handle into user context */
443*344aa361SAndroid Build Coastguard Worker ret = uctx_handle_install(ctx, port_handle, &handle_id);
444*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
445*344aa361SAndroid Build Coastguard Worker goto err_install;
446*344aa361SAndroid Build Coastguard Worker
447*344aa361SAndroid Build Coastguard Worker /* publish for normal operation */
448*344aa361SAndroid Build Coastguard Worker ret = ipc_port_publish(port_handle);
449*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
450*344aa361SAndroid Build Coastguard Worker goto err_publish;
451*344aa361SAndroid Build Coastguard Worker
452*344aa361SAndroid Build Coastguard Worker handle_decref(port_handle);
453*344aa361SAndroid Build Coastguard Worker return (long)handle_id;
454*344aa361SAndroid Build Coastguard Worker
455*344aa361SAndroid Build Coastguard Worker err_publish:
456*344aa361SAndroid Build Coastguard Worker (void)uctx_handle_remove(ctx, handle_id, NULL);
457*344aa361SAndroid Build Coastguard Worker err_install:
458*344aa361SAndroid Build Coastguard Worker handle_decref(port_handle);
459*344aa361SAndroid Build Coastguard Worker err_port_create:
460*344aa361SAndroid Build Coastguard Worker return (long)ret;
461*344aa361SAndroid Build Coastguard Worker }
462*344aa361SAndroid Build Coastguard Worker
463*344aa361SAndroid Build Coastguard Worker /*
464*344aa361SAndroid Build Coastguard Worker * Look up and port with given name (ipc_port_lock must be held)
465*344aa361SAndroid Build Coastguard Worker */
port_find_locked(const char * path)466*344aa361SAndroid Build Coastguard Worker static struct ipc_port* port_find_locked(const char* path) {
467*344aa361SAndroid Build Coastguard Worker struct ipc_port* port;
468*344aa361SAndroid Build Coastguard Worker
469*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(is_mutex_held(&ipc_port_lock));
470*344aa361SAndroid Build Coastguard Worker list_for_every_entry(&ipc_port_list, port, struct ipc_port, node) {
471*344aa361SAndroid Build Coastguard Worker if (!strcmp(path, port->path))
472*344aa361SAndroid Build Coastguard Worker return port;
473*344aa361SAndroid Build Coastguard Worker }
474*344aa361SAndroid Build Coastguard Worker return NULL;
475*344aa361SAndroid Build Coastguard Worker }
476*344aa361SAndroid Build Coastguard Worker
port_poll(struct handle * phandle,uint32_t emask,bool finalize)477*344aa361SAndroid Build Coastguard Worker static uint32_t port_poll(struct handle* phandle,
478*344aa361SAndroid Build Coastguard Worker uint32_t emask,
479*344aa361SAndroid Build Coastguard Worker bool finalize) {
480*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(phandle);
481*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(ipc_is_port(phandle));
482*344aa361SAndroid Build Coastguard Worker
483*344aa361SAndroid Build Coastguard Worker struct ipc_port* port = containerof(phandle, struct ipc_port, handle);
484*344aa361SAndroid Build Coastguard Worker uint32_t events = 0;
485*344aa361SAndroid Build Coastguard Worker
486*344aa361SAndroid Build Coastguard Worker if (port->state != IPC_PORT_STATE_LISTENING)
487*344aa361SAndroid Build Coastguard Worker events |= IPC_HANDLE_POLL_ERROR;
488*344aa361SAndroid Build Coastguard Worker else if (!list_is_empty(&port->pending_list))
489*344aa361SAndroid Build Coastguard Worker events |= IPC_HANDLE_POLL_READY;
490*344aa361SAndroid Build Coastguard Worker LTRACEF("%s in state %d events %x\n", port->path, port->state, events);
491*344aa361SAndroid Build Coastguard Worker
492*344aa361SAndroid Build Coastguard Worker return events & emask;
493*344aa361SAndroid Build Coastguard Worker }
494*344aa361SAndroid Build Coastguard Worker
495*344aa361SAndroid Build Coastguard Worker /*
496*344aa361SAndroid Build Coastguard Worker * Channel ref counting
497*344aa361SAndroid Build Coastguard Worker */
__chan_destroy_refobj(struct obj * ref)498*344aa361SAndroid Build Coastguard Worker static inline void __chan_destroy_refobj(struct obj* ref) {
499*344aa361SAndroid Build Coastguard Worker struct ipc_chan* chan = containerof(ref, struct ipc_chan, refobj);
500*344aa361SAndroid Build Coastguard Worker
501*344aa361SAndroid Build Coastguard Worker /* should not point to peer */
502*344aa361SAndroid Build Coastguard Worker ASSERT(chan->peer == NULL);
503*344aa361SAndroid Build Coastguard Worker
504*344aa361SAndroid Build Coastguard Worker /* should not be in a list */
505*344aa361SAndroid Build Coastguard Worker ASSERT(!list_in_list(&chan->node));
506*344aa361SAndroid Build Coastguard Worker
507*344aa361SAndroid Build Coastguard Worker if (chan->path)
508*344aa361SAndroid Build Coastguard Worker free((void*)chan->path);
509*344aa361SAndroid Build Coastguard Worker
510*344aa361SAndroid Build Coastguard Worker if (chan->msg_queue) {
511*344aa361SAndroid Build Coastguard Worker ipc_msg_queue_destroy(chan->msg_queue);
512*344aa361SAndroid Build Coastguard Worker chan->msg_queue = NULL;
513*344aa361SAndroid Build Coastguard Worker }
514*344aa361SAndroid Build Coastguard Worker free(chan);
515*344aa361SAndroid Build Coastguard Worker }
516*344aa361SAndroid Build Coastguard Worker
chan_add_ref(struct ipc_chan * chan,struct obj_ref * ref)517*344aa361SAndroid Build Coastguard Worker static inline void chan_add_ref(struct ipc_chan* chan, struct obj_ref* ref) {
518*344aa361SAndroid Build Coastguard Worker spin_lock_saved_state_t state;
519*344aa361SAndroid Build Coastguard Worker
520*344aa361SAndroid Build Coastguard Worker spin_lock_save(&chan->ref_slock, &state, SPIN_LOCK_FLAG_INTERRUPTS);
521*344aa361SAndroid Build Coastguard Worker obj_add_ref(&chan->refobj, ref);
522*344aa361SAndroid Build Coastguard Worker spin_unlock_restore(&chan->ref_slock, state, SPIN_LOCK_FLAG_INTERRUPTS);
523*344aa361SAndroid Build Coastguard Worker }
524*344aa361SAndroid Build Coastguard Worker
chan_del_ref(struct ipc_chan * chan,struct obj_ref * ref)525*344aa361SAndroid Build Coastguard Worker static inline void chan_del_ref(struct ipc_chan* chan, struct obj_ref* ref) {
526*344aa361SAndroid Build Coastguard Worker spin_lock_saved_state_t state;
527*344aa361SAndroid Build Coastguard Worker
528*344aa361SAndroid Build Coastguard Worker spin_lock_save(&chan->ref_slock, &state, SPIN_LOCK_FLAG_INTERRUPTS);
529*344aa361SAndroid Build Coastguard Worker bool last = obj_del_ref(&chan->refobj, ref, NULL);
530*344aa361SAndroid Build Coastguard Worker spin_unlock_restore(&chan->ref_slock, state, SPIN_LOCK_FLAG_INTERRUPTS);
531*344aa361SAndroid Build Coastguard Worker
532*344aa361SAndroid Build Coastguard Worker if (last)
533*344aa361SAndroid Build Coastguard Worker __chan_destroy_refobj(&chan->refobj);
534*344aa361SAndroid Build Coastguard Worker }
535*344aa361SAndroid Build Coastguard Worker
536*344aa361SAndroid Build Coastguard Worker /*
537*344aa361SAndroid Build Coastguard Worker * Initialize channel handle
538*344aa361SAndroid Build Coastguard Worker */
chan_handle_init(struct ipc_chan * chan)539*344aa361SAndroid Build Coastguard Worker static inline struct handle* chan_handle_init(struct ipc_chan* chan) {
540*344aa361SAndroid Build Coastguard Worker handle_init(&chan->handle, &ipc_chan_handle_ops);
541*344aa361SAndroid Build Coastguard Worker chan_add_ref(chan, &chan->handle_ref);
542*344aa361SAndroid Build Coastguard Worker return &chan->handle;
543*344aa361SAndroid Build Coastguard Worker }
544*344aa361SAndroid Build Coastguard Worker
545*344aa361SAndroid Build Coastguard Worker /*
546*344aa361SAndroid Build Coastguard Worker * Allocate and initialize new channel.
547*344aa361SAndroid Build Coastguard Worker */
chan_alloc(uint32_t flags,const uuid_t * uuid)548*344aa361SAndroid Build Coastguard Worker static struct ipc_chan* chan_alloc(uint32_t flags, const uuid_t* uuid) {
549*344aa361SAndroid Build Coastguard Worker struct ipc_chan* chan;
550*344aa361SAndroid Build Coastguard Worker struct obj_ref tmp_ref = OBJ_REF_INITIAL_VALUE(tmp_ref);
551*344aa361SAndroid Build Coastguard Worker
552*344aa361SAndroid Build Coastguard Worker chan = calloc(1, sizeof(struct ipc_chan));
553*344aa361SAndroid Build Coastguard Worker if (!chan)
554*344aa361SAndroid Build Coastguard Worker return NULL;
555*344aa361SAndroid Build Coastguard Worker
556*344aa361SAndroid Build Coastguard Worker /* init per channel mutex */
557*344aa361SAndroid Build Coastguard Worker mutex_init(&chan->mlock);
558*344aa361SAndroid Build Coastguard Worker
559*344aa361SAndroid Build Coastguard Worker /* init ref object and associated lock */
560*344aa361SAndroid Build Coastguard Worker spin_lock_init(&chan->ref_slock);
561*344aa361SAndroid Build Coastguard Worker obj_init(&chan->refobj, &tmp_ref);
562*344aa361SAndroid Build Coastguard Worker
563*344aa361SAndroid Build Coastguard Worker /* init refs */
564*344aa361SAndroid Build Coastguard Worker obj_ref_init(&chan->node_ref);
565*344aa361SAndroid Build Coastguard Worker obj_ref_init(&chan->peer_ref);
566*344aa361SAndroid Build Coastguard Worker obj_ref_init(&chan->handle_ref);
567*344aa361SAndroid Build Coastguard Worker
568*344aa361SAndroid Build Coastguard Worker chan->uuid = uuid;
569*344aa361SAndroid Build Coastguard Worker if (flags & IPC_CHAN_FLAG_SERVER)
570*344aa361SAndroid Build Coastguard Worker chan->state = IPC_CHAN_STATE_ACCEPTING;
571*344aa361SAndroid Build Coastguard Worker else
572*344aa361SAndroid Build Coastguard Worker chan->state = IPC_CHAN_STATE_CONNECTING;
573*344aa361SAndroid Build Coastguard Worker chan->flags = flags;
574*344aa361SAndroid Build Coastguard Worker
575*344aa361SAndroid Build Coastguard Worker chan_handle_init(chan);
576*344aa361SAndroid Build Coastguard Worker chan_del_ref(chan, &tmp_ref);
577*344aa361SAndroid Build Coastguard Worker
578*344aa361SAndroid Build Coastguard Worker return chan;
579*344aa361SAndroid Build Coastguard Worker }
580*344aa361SAndroid Build Coastguard Worker
chan_shutdown_locked(struct ipc_chan * chan)581*344aa361SAndroid Build Coastguard Worker static void chan_shutdown_locked(struct ipc_chan* chan) {
582*344aa361SAndroid Build Coastguard Worker /* Remove channel from any list it might be in */
583*344aa361SAndroid Build Coastguard Worker if (list_in_list(&chan->node)) {
584*344aa361SAndroid Build Coastguard Worker list_delete(&chan->node);
585*344aa361SAndroid Build Coastguard Worker chan_del_ref(chan, &chan->node_ref);
586*344aa361SAndroid Build Coastguard Worker
587*344aa361SAndroid Build Coastguard Worker if (chan->flags & IPC_CHAN_FLAG_SERVER) {
588*344aa361SAndroid Build Coastguard Worker /* If we are shutting down the server side of the channel pair
589*344aa361SAndroid Build Coastguard Worker * and it was in the list (assume accept pending_list) we also
590*344aa361SAndroid Build Coastguard Worker * need to remove handle ref because it is dangling. We cannot
591*344aa361SAndroid Build Coastguard Worker * call handle_decref here because of locks but we can just
592*344aa361SAndroid Build Coastguard Worker * remove chan_del_ref directly which would give us the same
593*344aa361SAndroid Build Coastguard Worker * effect. In addition we also should detach peer.
594*344aa361SAndroid Build Coastguard Worker */
595*344aa361SAndroid Build Coastguard Worker if (chan->peer) {
596*344aa361SAndroid Build Coastguard Worker chan_del_ref(chan->peer, &chan->peer_ref);
597*344aa361SAndroid Build Coastguard Worker chan->peer = NULL;
598*344aa361SAndroid Build Coastguard Worker }
599*344aa361SAndroid Build Coastguard Worker chan_del_ref(chan, &chan->handle_ref);
600*344aa361SAndroid Build Coastguard Worker }
601*344aa361SAndroid Build Coastguard Worker }
602*344aa361SAndroid Build Coastguard Worker
603*344aa361SAndroid Build Coastguard Worker switch (chan->state) {
604*344aa361SAndroid Build Coastguard Worker case IPC_CHAN_STATE_CONNECTED:
605*344aa361SAndroid Build Coastguard Worker case IPC_CHAN_STATE_CONNECTING:
606*344aa361SAndroid Build Coastguard Worker chan->state = IPC_CHAN_STATE_DISCONNECTING;
607*344aa361SAndroid Build Coastguard Worker handle_notify(&chan->handle);
608*344aa361SAndroid Build Coastguard Worker break;
609*344aa361SAndroid Build Coastguard Worker case IPC_CHAN_STATE_ACCEPTING:
610*344aa361SAndroid Build Coastguard Worker chan->state = IPC_CHAN_STATE_DISCONNECTING;
611*344aa361SAndroid Build Coastguard Worker break;
612*344aa361SAndroid Build Coastguard Worker default:
613*344aa361SAndroid Build Coastguard Worker /* no op */
614*344aa361SAndroid Build Coastguard Worker break;
615*344aa361SAndroid Build Coastguard Worker }
616*344aa361SAndroid Build Coastguard Worker }
617*344aa361SAndroid Build Coastguard Worker
chan_shutdown(struct ipc_chan * chan)618*344aa361SAndroid Build Coastguard Worker static void chan_shutdown(struct ipc_chan* chan) {
619*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(is_mutex_held(&ipc_port_lock));
620*344aa361SAndroid Build Coastguard Worker
621*344aa361SAndroid Build Coastguard Worker LTRACEF("chan %p: peer %p\n", chan, chan->peer);
622*344aa361SAndroid Build Coastguard Worker
623*344aa361SAndroid Build Coastguard Worker mutex_acquire(&chan->mlock);
624*344aa361SAndroid Build Coastguard Worker struct ipc_chan* peer = chan->peer;
625*344aa361SAndroid Build Coastguard Worker chan->peer = NULL;
626*344aa361SAndroid Build Coastguard Worker chan_shutdown_locked(chan);
627*344aa361SAndroid Build Coastguard Worker mutex_release(&chan->mlock);
628*344aa361SAndroid Build Coastguard Worker
629*344aa361SAndroid Build Coastguard Worker /*
630*344aa361SAndroid Build Coastguard Worker * if peer exists we are still holding reference to peer chan object
631*344aa361SAndroid Build Coastguard Worker * so it cannot disappear.
632*344aa361SAndroid Build Coastguard Worker */
633*344aa361SAndroid Build Coastguard Worker if (peer) {
634*344aa361SAndroid Build Coastguard Worker /* shutdown peer */
635*344aa361SAndroid Build Coastguard Worker mutex_acquire(&peer->mlock);
636*344aa361SAndroid Build Coastguard Worker chan_shutdown_locked(peer);
637*344aa361SAndroid Build Coastguard Worker mutex_release(&peer->mlock);
638*344aa361SAndroid Build Coastguard Worker chan_del_ref(peer, &chan->peer_ref);
639*344aa361SAndroid Build Coastguard Worker }
640*344aa361SAndroid Build Coastguard Worker }
641*344aa361SAndroid Build Coastguard Worker
chan_handle_destroy(struct handle * chandle)642*344aa361SAndroid Build Coastguard Worker static void chan_handle_destroy(struct handle* chandle) {
643*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(chandle);
644*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(ipc_is_channel(chandle));
645*344aa361SAndroid Build Coastguard Worker
646*344aa361SAndroid Build Coastguard Worker struct ipc_chan* chan = containerof(chandle, struct ipc_chan, handle);
647*344aa361SAndroid Build Coastguard Worker
648*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
649*344aa361SAndroid Build Coastguard Worker chan_shutdown(chan);
650*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
651*344aa361SAndroid Build Coastguard Worker
652*344aa361SAndroid Build Coastguard Worker chan_del_ref(chan, &chan->handle_ref);
653*344aa361SAndroid Build Coastguard Worker }
654*344aa361SAndroid Build Coastguard Worker
655*344aa361SAndroid Build Coastguard Worker /*
656*344aa361SAndroid Build Coastguard Worker * Poll channel state
657*344aa361SAndroid Build Coastguard Worker */
chan_poll(struct handle * chandle,uint32_t emask,bool finalize)658*344aa361SAndroid Build Coastguard Worker static uint32_t chan_poll(struct handle* chandle,
659*344aa361SAndroid Build Coastguard Worker uint32_t emask,
660*344aa361SAndroid Build Coastguard Worker bool finalize) {
661*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(chandle);
662*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(ipc_is_channel(chandle));
663*344aa361SAndroid Build Coastguard Worker
664*344aa361SAndroid Build Coastguard Worker struct ipc_chan* chan = containerof(chandle, struct ipc_chan, handle);
665*344aa361SAndroid Build Coastguard Worker
666*344aa361SAndroid Build Coastguard Worker uint32_t events = 0;
667*344aa361SAndroid Build Coastguard Worker
668*344aa361SAndroid Build Coastguard Worker mutex_acquire(&chan->mlock);
669*344aa361SAndroid Build Coastguard Worker /* peer is closing connection */
670*344aa361SAndroid Build Coastguard Worker if (chan->state == IPC_CHAN_STATE_DISCONNECTING) {
671*344aa361SAndroid Build Coastguard Worker events |= IPC_HANDLE_POLL_HUP;
672*344aa361SAndroid Build Coastguard Worker }
673*344aa361SAndroid Build Coastguard Worker
674*344aa361SAndroid Build Coastguard Worker /* server accepted our connection */
675*344aa361SAndroid Build Coastguard Worker if (chan->aux_state & IPC_CHAN_AUX_STATE_CONNECTED) {
676*344aa361SAndroid Build Coastguard Worker events |= IPC_HANDLE_POLL_READY;
677*344aa361SAndroid Build Coastguard Worker }
678*344aa361SAndroid Build Coastguard Worker
679*344aa361SAndroid Build Coastguard Worker /* have a pending message? */
680*344aa361SAndroid Build Coastguard Worker if (chan->msg_queue && !ipc_msg_queue_is_empty(chan->msg_queue)) {
681*344aa361SAndroid Build Coastguard Worker events |= IPC_HANDLE_POLL_MSG;
682*344aa361SAndroid Build Coastguard Worker }
683*344aa361SAndroid Build Coastguard Worker
684*344aa361SAndroid Build Coastguard Worker /* check if we were send blocked */
685*344aa361SAndroid Build Coastguard Worker if (chan->aux_state & IPC_CHAN_AUX_STATE_SEND_UNBLOCKED) {
686*344aa361SAndroid Build Coastguard Worker events |= IPC_HANDLE_POLL_SEND_UNBLOCKED;
687*344aa361SAndroid Build Coastguard Worker }
688*344aa361SAndroid Build Coastguard Worker
689*344aa361SAndroid Build Coastguard Worker events &= emask;
690*344aa361SAndroid Build Coastguard Worker if (finalize) {
691*344aa361SAndroid Build Coastguard Worker if (events & IPC_HANDLE_POLL_READY) {
692*344aa361SAndroid Build Coastguard Worker chan->aux_state &= ~IPC_CHAN_AUX_STATE_CONNECTED;
693*344aa361SAndroid Build Coastguard Worker }
694*344aa361SAndroid Build Coastguard Worker if (events & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
695*344aa361SAndroid Build Coastguard Worker chan->aux_state &= ~IPC_CHAN_AUX_STATE_SEND_UNBLOCKED;
696*344aa361SAndroid Build Coastguard Worker }
697*344aa361SAndroid Build Coastguard Worker }
698*344aa361SAndroid Build Coastguard Worker
699*344aa361SAndroid Build Coastguard Worker mutex_release(&chan->mlock);
700*344aa361SAndroid Build Coastguard Worker return events;
701*344aa361SAndroid Build Coastguard Worker }
702*344aa361SAndroid Build Coastguard Worker
703*344aa361SAndroid Build Coastguard Worker /*
704*344aa361SAndroid Build Coastguard Worker * Check if connection to specified port is allowed
705*344aa361SAndroid Build Coastguard Worker */
ipc_port_check_access(uint32_t port_flags,const uuid_t * uuid)706*344aa361SAndroid Build Coastguard Worker int ipc_port_check_access(uint32_t port_flags, const uuid_t* uuid) {
707*344aa361SAndroid Build Coastguard Worker if (!uuid)
708*344aa361SAndroid Build Coastguard Worker return ERR_ACCESS_DENIED;
709*344aa361SAndroid Build Coastguard Worker
710*344aa361SAndroid Build Coastguard Worker if (is_ns_client(uuid)) {
711*344aa361SAndroid Build Coastguard Worker /* check if this port allows connection from NS clients */
712*344aa361SAndroid Build Coastguard Worker if (port_flags & IPC_PORT_ALLOW_NS_CONNECT)
713*344aa361SAndroid Build Coastguard Worker return NO_ERROR;
714*344aa361SAndroid Build Coastguard Worker } else {
715*344aa361SAndroid Build Coastguard Worker /* check if this port allows connection from Trusted Apps */
716*344aa361SAndroid Build Coastguard Worker if (port_flags & IPC_PORT_ALLOW_TA_CONNECT)
717*344aa361SAndroid Build Coastguard Worker return NO_ERROR;
718*344aa361SAndroid Build Coastguard Worker }
719*344aa361SAndroid Build Coastguard Worker
720*344aa361SAndroid Build Coastguard Worker return ERR_ACCESS_DENIED;
721*344aa361SAndroid Build Coastguard Worker }
722*344aa361SAndroid Build Coastguard Worker
port_attach_client(struct ipc_port * port,struct ipc_chan * client)723*344aa361SAndroid Build Coastguard Worker static int port_attach_client(struct ipc_port* port, struct ipc_chan* client) {
724*344aa361SAndroid Build Coastguard Worker int ret;
725*344aa361SAndroid Build Coastguard Worker struct ipc_chan* server;
726*344aa361SAndroid Build Coastguard Worker
727*344aa361SAndroid Build Coastguard Worker if (port->state != IPC_PORT_STATE_LISTENING) {
728*344aa361SAndroid Build Coastguard Worker LTRACEF("port %s is not in listening state (%d)\n", port->path,
729*344aa361SAndroid Build Coastguard Worker port->state);
730*344aa361SAndroid Build Coastguard Worker return ERR_NOT_READY;
731*344aa361SAndroid Build Coastguard Worker }
732*344aa361SAndroid Build Coastguard Worker
733*344aa361SAndroid Build Coastguard Worker /* check if we are allowed to connect */
734*344aa361SAndroid Build Coastguard Worker ret = ipc_port_check_access(port->flags, client->uuid);
735*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR) {
736*344aa361SAndroid Build Coastguard Worker LTRACEF("access denied: %d\n", ret);
737*344aa361SAndroid Build Coastguard Worker return ret;
738*344aa361SAndroid Build Coastguard Worker }
739*344aa361SAndroid Build Coastguard Worker
740*344aa361SAndroid Build Coastguard Worker server = chan_alloc(IPC_CHAN_FLAG_SERVER, port->uuid);
741*344aa361SAndroid Build Coastguard Worker if (!server) {
742*344aa361SAndroid Build Coastguard Worker LTRACEF("failed to alloc server\n");
743*344aa361SAndroid Build Coastguard Worker return ERR_NO_MEMORY;
744*344aa361SAndroid Build Coastguard Worker }
745*344aa361SAndroid Build Coastguard Worker
746*344aa361SAndroid Build Coastguard Worker /* allocate msg queues */
747*344aa361SAndroid Build Coastguard Worker ret = ipc_msg_queue_create(port->num_recv_bufs, port->recv_buf_size,
748*344aa361SAndroid Build Coastguard Worker &client->msg_queue);
749*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR) {
750*344aa361SAndroid Build Coastguard Worker LTRACEF("failed to alloc mq: %d\n", ret);
751*344aa361SAndroid Build Coastguard Worker goto err_client_mq;
752*344aa361SAndroid Build Coastguard Worker }
753*344aa361SAndroid Build Coastguard Worker
754*344aa361SAndroid Build Coastguard Worker ret = ipc_msg_queue_create(port->num_recv_bufs, port->recv_buf_size,
755*344aa361SAndroid Build Coastguard Worker &server->msg_queue);
756*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR) {
757*344aa361SAndroid Build Coastguard Worker LTRACEF("failed to alloc mq: %d\n", ret);
758*344aa361SAndroid Build Coastguard Worker goto err_server_mq;
759*344aa361SAndroid Build Coastguard Worker }
760*344aa361SAndroid Build Coastguard Worker
761*344aa361SAndroid Build Coastguard Worker /* setup cross peer refs */
762*344aa361SAndroid Build Coastguard Worker mutex_acquire(&client->mlock);
763*344aa361SAndroid Build Coastguard Worker if (client->state == IPC_CHAN_STATE_DISCONNECTING) {
764*344aa361SAndroid Build Coastguard Worker mutex_release(&client->mlock);
765*344aa361SAndroid Build Coastguard Worker goto err_closed;
766*344aa361SAndroid Build Coastguard Worker }
767*344aa361SAndroid Build Coastguard Worker chan_add_ref(server, &client->peer_ref);
768*344aa361SAndroid Build Coastguard Worker client->peer = server;
769*344aa361SAndroid Build Coastguard Worker
770*344aa361SAndroid Build Coastguard Worker chan_add_ref(client, &server->peer_ref);
771*344aa361SAndroid Build Coastguard Worker server->peer = client;
772*344aa361SAndroid Build Coastguard Worker mutex_release(&client->mlock);
773*344aa361SAndroid Build Coastguard Worker
774*344aa361SAndroid Build Coastguard Worker /* and add server channel to pending connection list */
775*344aa361SAndroid Build Coastguard Worker chan_add_ref(server, &server->node_ref);
776*344aa361SAndroid Build Coastguard Worker list_add_tail(&port->pending_list, &server->node);
777*344aa361SAndroid Build Coastguard Worker
778*344aa361SAndroid Build Coastguard Worker /* Notify port that there is a pending connection */
779*344aa361SAndroid Build Coastguard Worker handle_notify(&port->handle);
780*344aa361SAndroid Build Coastguard Worker
781*344aa361SAndroid Build Coastguard Worker return NO_ERROR;
782*344aa361SAndroid Build Coastguard Worker
783*344aa361SAndroid Build Coastguard Worker err_closed:
784*344aa361SAndroid Build Coastguard Worker err_server_mq:
785*344aa361SAndroid Build Coastguard Worker err_client_mq:
786*344aa361SAndroid Build Coastguard Worker /*
787*344aa361SAndroid Build Coastguard Worker * Ideally this would call handle_decref(&server->handle), but that will
788*344aa361SAndroid Build Coastguard Worker * deadlock as ipc_port_lock is already held. Therefore close directly.
789*344aa361SAndroid Build Coastguard Worker */
790*344aa361SAndroid Build Coastguard Worker chan_shutdown(server);
791*344aa361SAndroid Build Coastguard Worker chan_del_ref(server, &server->handle_ref);
792*344aa361SAndroid Build Coastguard Worker
793*344aa361SAndroid Build Coastguard Worker return ERR_NO_MEMORY;
794*344aa361SAndroid Build Coastguard Worker }
795*344aa361SAndroid Build Coastguard Worker
796*344aa361SAndroid Build Coastguard Worker /*
797*344aa361SAndroid Build Coastguard Worker * Client requests a connection to a port. It can be called in context
798*344aa361SAndroid Build Coastguard Worker * of user task as well as vdev RX thread.
799*344aa361SAndroid Build Coastguard Worker */
ipc_port_connect_async(const uuid_t * cid,const char * path,size_t max_path,uint flags,struct handle ** chandle_ptr)800*344aa361SAndroid Build Coastguard Worker int ipc_port_connect_async(const uuid_t* cid,
801*344aa361SAndroid Build Coastguard Worker const char* path,
802*344aa361SAndroid Build Coastguard Worker size_t max_path,
803*344aa361SAndroid Build Coastguard Worker uint flags,
804*344aa361SAndroid Build Coastguard Worker struct handle** chandle_ptr) {
805*344aa361SAndroid Build Coastguard Worker struct ipc_port* port;
806*344aa361SAndroid Build Coastguard Worker struct ipc_chan* client;
807*344aa361SAndroid Build Coastguard Worker int ret;
808*344aa361SAndroid Build Coastguard Worker
809*344aa361SAndroid Build Coastguard Worker if (!cid) {
810*344aa361SAndroid Build Coastguard Worker /* client uuid is required */
811*344aa361SAndroid Build Coastguard Worker TRACEF("client uuid is required\n");
812*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
813*344aa361SAndroid Build Coastguard Worker }
814*344aa361SAndroid Build Coastguard Worker
815*344aa361SAndroid Build Coastguard Worker size_t len = strnlen(path, max_path);
816*344aa361SAndroid Build Coastguard Worker if (len == 0 || len >= max_path) {
817*344aa361SAndroid Build Coastguard Worker /* unterminated string */
818*344aa361SAndroid Build Coastguard Worker TRACEF("invalid path specified\n");
819*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
820*344aa361SAndroid Build Coastguard Worker }
821*344aa361SAndroid Build Coastguard Worker /* After this point path is zero terminated */
822*344aa361SAndroid Build Coastguard Worker
823*344aa361SAndroid Build Coastguard Worker /* allocate channel pair */
824*344aa361SAndroid Build Coastguard Worker client = chan_alloc(0, cid);
825*344aa361SAndroid Build Coastguard Worker if (!client) {
826*344aa361SAndroid Build Coastguard Worker TRACEF("failed to alloc client\n");
827*344aa361SAndroid Build Coastguard Worker return ERR_NO_MEMORY;
828*344aa361SAndroid Build Coastguard Worker }
829*344aa361SAndroid Build Coastguard Worker
830*344aa361SAndroid Build Coastguard Worker LTRACEF("Connecting to '%s'\n", path);
831*344aa361SAndroid Build Coastguard Worker
832*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
833*344aa361SAndroid Build Coastguard Worker
834*344aa361SAndroid Build Coastguard Worker port = port_find_locked(path);
835*344aa361SAndroid Build Coastguard Worker if (port) {
836*344aa361SAndroid Build Coastguard Worker /* found */
837*344aa361SAndroid Build Coastguard Worker ret = port_attach_client(port, client);
838*344aa361SAndroid Build Coastguard Worker if (ret)
839*344aa361SAndroid Build Coastguard Worker goto err_attach_client;
840*344aa361SAndroid Build Coastguard Worker } else {
841*344aa361SAndroid Build Coastguard Worker /*
842*344aa361SAndroid Build Coastguard Worker * Check if an app has registered to be started on connections
843*344aa361SAndroid Build Coastguard Worker * to this port
844*344aa361SAndroid Build Coastguard Worker */
845*344aa361SAndroid Build Coastguard Worker ret = trusty_app_request_start_by_port(path, cid);
846*344aa361SAndroid Build Coastguard Worker switch (ret) {
847*344aa361SAndroid Build Coastguard Worker case NO_ERROR:
848*344aa361SAndroid Build Coastguard Worker case ERR_ALREADY_STARTED:
849*344aa361SAndroid Build Coastguard Worker break;
850*344aa361SAndroid Build Coastguard Worker case ERR_NOT_FOUND:
851*344aa361SAndroid Build Coastguard Worker /*
852*344aa361SAndroid Build Coastguard Worker * App has not been loaded yet, but we wait for it if the caller
853*344aa361SAndroid Build Coastguard Worker * asked to
854*344aa361SAndroid Build Coastguard Worker */
855*344aa361SAndroid Build Coastguard Worker if (flags & IPC_CONNECT_WAIT_FOR_PORT) {
856*344aa361SAndroid Build Coastguard Worker break;
857*344aa361SAndroid Build Coastguard Worker }
858*344aa361SAndroid Build Coastguard Worker __FALLTHROUGH;
859*344aa361SAndroid Build Coastguard Worker default:
860*344aa361SAndroid Build Coastguard Worker goto err_find_ports;
861*344aa361SAndroid Build Coastguard Worker }
862*344aa361SAndroid Build Coastguard Worker
863*344aa361SAndroid Build Coastguard Worker /* port not found, add connection to waiting_for_port_chan_list */
864*344aa361SAndroid Build Coastguard Worker client->path = strdup(path);
865*344aa361SAndroid Build Coastguard Worker if (!client->path) {
866*344aa361SAndroid Build Coastguard Worker ret = ERR_NO_MEMORY;
867*344aa361SAndroid Build Coastguard Worker goto err_alloc_path;
868*344aa361SAndroid Build Coastguard Worker }
869*344aa361SAndroid Build Coastguard Worker
870*344aa361SAndroid Build Coastguard Worker /* add it to waiting for port list */
871*344aa361SAndroid Build Coastguard Worker add_to_waiting_for_port_list_locked(client);
872*344aa361SAndroid Build Coastguard Worker }
873*344aa361SAndroid Build Coastguard Worker
874*344aa361SAndroid Build Coastguard Worker LTRACEF("new connection: client %p: peer %p\n", client, client->peer);
875*344aa361SAndroid Build Coastguard Worker
876*344aa361SAndroid Build Coastguard Worker /* success */
877*344aa361SAndroid Build Coastguard Worker handle_incref(&client->handle);
878*344aa361SAndroid Build Coastguard Worker *chandle_ptr = &client->handle;
879*344aa361SAndroid Build Coastguard Worker ret = NO_ERROR;
880*344aa361SAndroid Build Coastguard Worker
881*344aa361SAndroid Build Coastguard Worker err_alloc_path:
882*344aa361SAndroid Build Coastguard Worker err_attach_client:
883*344aa361SAndroid Build Coastguard Worker err_find_ports:
884*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
885*344aa361SAndroid Build Coastguard Worker handle_decref(&client->handle);
886*344aa361SAndroid Build Coastguard Worker return ret;
887*344aa361SAndroid Build Coastguard Worker }
888*344aa361SAndroid Build Coastguard Worker
889*344aa361SAndroid Build Coastguard Worker /* returns handle id for the new channel */
890*344aa361SAndroid Build Coastguard Worker
891*344aa361SAndroid Build Coastguard Worker #ifndef DEFAULT_IPC_CONNECT_WARN_TIMEOUT
892*344aa361SAndroid Build Coastguard Worker #define DEFAULT_IPC_CONNECT_WARN_TIMEOUT INFINITE_TIME
893*344aa361SAndroid Build Coastguard Worker #endif
894*344aa361SAndroid Build Coastguard Worker
sys_connect(user_addr_t path,uint32_t flags)895*344aa361SAndroid Build Coastguard Worker long __SYSCALL sys_connect(user_addr_t path, uint32_t flags) {
896*344aa361SAndroid Build Coastguard Worker struct trusty_app* tapp = current_trusty_app();
897*344aa361SAndroid Build Coastguard Worker struct uctx* ctx = current_uctx();
898*344aa361SAndroid Build Coastguard Worker struct handle* chandle;
899*344aa361SAndroid Build Coastguard Worker char tmp_path[IPC_PORT_PATH_MAX];
900*344aa361SAndroid Build Coastguard Worker int ret;
901*344aa361SAndroid Build Coastguard Worker handle_id_t handle_id;
902*344aa361SAndroid Build Coastguard Worker
903*344aa361SAndroid Build Coastguard Worker if (flags & ~IPC_CONNECT_MASK) {
904*344aa361SAndroid Build Coastguard Worker /* unsupported flags specified */
905*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
906*344aa361SAndroid Build Coastguard Worker }
907*344aa361SAndroid Build Coastguard Worker
908*344aa361SAndroid Build Coastguard Worker ret = (int)strlcpy_from_user(tmp_path, path, sizeof(tmp_path));
909*344aa361SAndroid Build Coastguard Worker if (ret < 0)
910*344aa361SAndroid Build Coastguard Worker return (long)ret;
911*344aa361SAndroid Build Coastguard Worker
912*344aa361SAndroid Build Coastguard Worker if ((uint)ret >= sizeof(tmp_path))
913*344aa361SAndroid Build Coastguard Worker return (long)ERR_INVALID_ARGS;
914*344aa361SAndroid Build Coastguard Worker
915*344aa361SAndroid Build Coastguard Worker /* try to connect to event first */
916*344aa361SAndroid Build Coastguard Worker ret = event_source_open(&tapp->props.uuid, tmp_path, sizeof(tmp_path), 0,
917*344aa361SAndroid Build Coastguard Worker &chandle);
918*344aa361SAndroid Build Coastguard Worker if (ret == NO_ERROR) {
919*344aa361SAndroid Build Coastguard Worker goto install;
920*344aa361SAndroid Build Coastguard Worker }
921*344aa361SAndroid Build Coastguard Worker
922*344aa361SAndroid Build Coastguard Worker /* if an error is other then ERR_NOT_FOUND return immediately */
923*344aa361SAndroid Build Coastguard Worker if (ret != ERR_NOT_FOUND) {
924*344aa361SAndroid Build Coastguard Worker return ret;
925*344aa361SAndroid Build Coastguard Worker }
926*344aa361SAndroid Build Coastguard Worker
927*344aa361SAndroid Build Coastguard Worker /* then regular port */
928*344aa361SAndroid Build Coastguard Worker ret = ipc_port_connect_async(&tapp->props.uuid, tmp_path, sizeof(tmp_path),
929*344aa361SAndroid Build Coastguard Worker flags, &chandle);
930*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
931*344aa361SAndroid Build Coastguard Worker return (long)ret;
932*344aa361SAndroid Build Coastguard Worker
933*344aa361SAndroid Build Coastguard Worker if (!(flags & IPC_CONNECT_ASYNC)) {
934*344aa361SAndroid Build Coastguard Worker uint32_t event;
935*344aa361SAndroid Build Coastguard Worker lk_time_t timeout_msecs = DEFAULT_IPC_CONNECT_WARN_TIMEOUT;
936*344aa361SAndroid Build Coastguard Worker
937*344aa361SAndroid Build Coastguard Worker ret = handle_wait(chandle, &event, timeout_msecs);
938*344aa361SAndroid Build Coastguard Worker if (ret == ERR_TIMED_OUT) {
939*344aa361SAndroid Build Coastguard Worker TRACEF("Timedout connecting to %s\n", tmp_path);
940*344aa361SAndroid Build Coastguard Worker ret = handle_wait(chandle, &event, INFINITE_TIME);
941*344aa361SAndroid Build Coastguard Worker }
942*344aa361SAndroid Build Coastguard Worker
943*344aa361SAndroid Build Coastguard Worker if (ret < 0) {
944*344aa361SAndroid Build Coastguard Worker /* timeout or other error */
945*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
946*344aa361SAndroid Build Coastguard Worker return ret;
947*344aa361SAndroid Build Coastguard Worker }
948*344aa361SAndroid Build Coastguard Worker
949*344aa361SAndroid Build Coastguard Worker if ((event & IPC_HANDLE_POLL_HUP) && !(event & IPC_HANDLE_POLL_MSG)) {
950*344aa361SAndroid Build Coastguard Worker /* hangup and no pending messages */
951*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
952*344aa361SAndroid Build Coastguard Worker return ERR_CHANNEL_CLOSED;
953*344aa361SAndroid Build Coastguard Worker }
954*344aa361SAndroid Build Coastguard Worker
955*344aa361SAndroid Build Coastguard Worker if (!(event & IPC_HANDLE_POLL_READY)) {
956*344aa361SAndroid Build Coastguard Worker /* not connected */
957*344aa361SAndroid Build Coastguard Worker TRACEF("Unexpected channel state: event = 0x%x\n", event);
958*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
959*344aa361SAndroid Build Coastguard Worker return ERR_NOT_READY;
960*344aa361SAndroid Build Coastguard Worker }
961*344aa361SAndroid Build Coastguard Worker }
962*344aa361SAndroid Build Coastguard Worker
963*344aa361SAndroid Build Coastguard Worker install:
964*344aa361SAndroid Build Coastguard Worker ret = uctx_handle_install(ctx, chandle, &handle_id);
965*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR) {
966*344aa361SAndroid Build Coastguard Worker /* Failed to install handle into user context */
967*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
968*344aa361SAndroid Build Coastguard Worker return (long)ret;
969*344aa361SAndroid Build Coastguard Worker }
970*344aa361SAndroid Build Coastguard Worker
971*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
972*344aa361SAndroid Build Coastguard Worker return (long)handle_id;
973*344aa361SAndroid Build Coastguard Worker }
974*344aa361SAndroid Build Coastguard Worker
975*344aa361SAndroid Build Coastguard Worker /*
976*344aa361SAndroid Build Coastguard Worker * Called by user task to accept incomming connection
977*344aa361SAndroid Build Coastguard Worker */
ipc_port_accept(struct handle * phandle,struct handle ** chandle_ptr,const uuid_t ** uuid_ptr)978*344aa361SAndroid Build Coastguard Worker int ipc_port_accept(struct handle* phandle,
979*344aa361SAndroid Build Coastguard Worker struct handle** chandle_ptr,
980*344aa361SAndroid Build Coastguard Worker const uuid_t** uuid_ptr) {
981*344aa361SAndroid Build Coastguard Worker struct ipc_port* port;
982*344aa361SAndroid Build Coastguard Worker struct ipc_chan* server = NULL;
983*344aa361SAndroid Build Coastguard Worker struct ipc_chan* client = NULL;
984*344aa361SAndroid Build Coastguard Worker
985*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(chandle_ptr);
986*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(uuid_ptr);
987*344aa361SAndroid Build Coastguard Worker
988*344aa361SAndroid Build Coastguard Worker if (!phandle || !ipc_is_port(phandle)) {
989*344aa361SAndroid Build Coastguard Worker LTRACEF("invalid port handle %p\n", phandle);
990*344aa361SAndroid Build Coastguard Worker return ERR_INVALID_ARGS;
991*344aa361SAndroid Build Coastguard Worker }
992*344aa361SAndroid Build Coastguard Worker
993*344aa361SAndroid Build Coastguard Worker port = containerof(phandle, struct ipc_port, handle);
994*344aa361SAndroid Build Coastguard Worker
995*344aa361SAndroid Build Coastguard Worker if (port->state != IPC_PORT_STATE_LISTENING) {
996*344aa361SAndroid Build Coastguard Worker /* Not in listening state: caller should close port.
997*344aa361SAndroid Build Coastguard Worker * is it really possible to get here?
998*344aa361SAndroid Build Coastguard Worker */
999*344aa361SAndroid Build Coastguard Worker return ERR_CHANNEL_CLOSED;
1000*344aa361SAndroid Build Coastguard Worker }
1001*344aa361SAndroid Build Coastguard Worker
1002*344aa361SAndroid Build Coastguard Worker /* get next pending connection */
1003*344aa361SAndroid Build Coastguard Worker mutex_acquire(&ipc_port_lock);
1004*344aa361SAndroid Build Coastguard Worker server = list_remove_head_type(&port->pending_list, struct ipc_chan, node);
1005*344aa361SAndroid Build Coastguard Worker mutex_release(&ipc_port_lock);
1006*344aa361SAndroid Build Coastguard Worker if (!server) {
1007*344aa361SAndroid Build Coastguard Worker /* TODO: should we block waiting for a new connection if one
1008*344aa361SAndroid Build Coastguard Worker * is not pending? if so, need an optional argument maybe.
1009*344aa361SAndroid Build Coastguard Worker */
1010*344aa361SAndroid Build Coastguard Worker return ERR_NO_MSG;
1011*344aa361SAndroid Build Coastguard Worker }
1012*344aa361SAndroid Build Coastguard Worker
1013*344aa361SAndroid Build Coastguard Worker /* it must be a server side channel */
1014*344aa361SAndroid Build Coastguard Worker DEBUG_ASSERT(server->flags & IPC_CHAN_FLAG_SERVER);
1015*344aa361SAndroid Build Coastguard Worker
1016*344aa361SAndroid Build Coastguard Worker chan_del_ref(server, &server->node_ref); /* drop list ref */
1017*344aa361SAndroid Build Coastguard Worker
1018*344aa361SAndroid Build Coastguard Worker client = server->peer;
1019*344aa361SAndroid Build Coastguard Worker
1020*344aa361SAndroid Build Coastguard Worker /* there must be a client, it must be in CONNECTING state and
1021*344aa361SAndroid Build Coastguard Worker server must be in ACCEPTING state */
1022*344aa361SAndroid Build Coastguard Worker ASSERT(client);
1023*344aa361SAndroid Build Coastguard Worker mutex_acquire(&client->mlock);
1024*344aa361SAndroid Build Coastguard Worker if (server->state != IPC_CHAN_STATE_ACCEPTING ||
1025*344aa361SAndroid Build Coastguard Worker client->state != IPC_CHAN_STATE_CONNECTING) {
1026*344aa361SAndroid Build Coastguard Worker LTRACEF("Drop connection: client %p (0x%x) to server %p (0x%x):\n",
1027*344aa361SAndroid Build Coastguard Worker client, client->state, server, server->state);
1028*344aa361SAndroid Build Coastguard Worker mutex_release(&client->mlock);
1029*344aa361SAndroid Build Coastguard Worker handle_decref(&server->handle);
1030*344aa361SAndroid Build Coastguard Worker return ERR_CHANNEL_CLOSED;
1031*344aa361SAndroid Build Coastguard Worker }
1032*344aa361SAndroid Build Coastguard Worker
1033*344aa361SAndroid Build Coastguard Worker /* move both client and server into connected state */
1034*344aa361SAndroid Build Coastguard Worker server->state = IPC_CHAN_STATE_CONNECTED;
1035*344aa361SAndroid Build Coastguard Worker client->state = IPC_CHAN_STATE_CONNECTED;
1036*344aa361SAndroid Build Coastguard Worker client->aux_state |= IPC_CHAN_AUX_STATE_CONNECTED;
1037*344aa361SAndroid Build Coastguard Worker
1038*344aa361SAndroid Build Coastguard Worker /* init server channel handle and return it to caller */
1039*344aa361SAndroid Build Coastguard Worker *chandle_ptr = &server->handle;
1040*344aa361SAndroid Build Coastguard Worker *uuid_ptr = client->uuid;
1041*344aa361SAndroid Build Coastguard Worker
1042*344aa361SAndroid Build Coastguard Worker mutex_release(&client->mlock);
1043*344aa361SAndroid Build Coastguard Worker
1044*344aa361SAndroid Build Coastguard Worker /* notify client */
1045*344aa361SAndroid Build Coastguard Worker handle_notify(&client->handle);
1046*344aa361SAndroid Build Coastguard Worker
1047*344aa361SAndroid Build Coastguard Worker return NO_ERROR;
1048*344aa361SAndroid Build Coastguard Worker }
1049*344aa361SAndroid Build Coastguard Worker
sys_accept(uint32_t handle_id,user_addr_t user_uuid)1050*344aa361SAndroid Build Coastguard Worker long __SYSCALL sys_accept(uint32_t handle_id, user_addr_t user_uuid) {
1051*344aa361SAndroid Build Coastguard Worker struct uctx* ctx = current_uctx();
1052*344aa361SAndroid Build Coastguard Worker struct handle* phandle = NULL;
1053*344aa361SAndroid Build Coastguard Worker struct handle* chandle = NULL;
1054*344aa361SAndroid Build Coastguard Worker int ret;
1055*344aa361SAndroid Build Coastguard Worker handle_id_t new_id;
1056*344aa361SAndroid Build Coastguard Worker const uuid_t* peer_uuid_ptr;
1057*344aa361SAndroid Build Coastguard Worker
1058*344aa361SAndroid Build Coastguard Worker ret = uctx_handle_get(ctx, handle_id, &phandle);
1059*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
1060*344aa361SAndroid Build Coastguard Worker return (long)ret;
1061*344aa361SAndroid Build Coastguard Worker
1062*344aa361SAndroid Build Coastguard Worker ret = ipc_port_accept(phandle, &chandle, &peer_uuid_ptr);
1063*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
1064*344aa361SAndroid Build Coastguard Worker goto err_accept;
1065*344aa361SAndroid Build Coastguard Worker
1066*344aa361SAndroid Build Coastguard Worker ret = uctx_handle_install(ctx, chandle, &new_id);
1067*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
1068*344aa361SAndroid Build Coastguard Worker goto err_install;
1069*344aa361SAndroid Build Coastguard Worker
1070*344aa361SAndroid Build Coastguard Worker /* copy peer uuid into userspace */
1071*344aa361SAndroid Build Coastguard Worker ret = copy_to_user(user_uuid, peer_uuid_ptr, sizeof(uuid_t));
1072*344aa361SAndroid Build Coastguard Worker if (ret != NO_ERROR)
1073*344aa361SAndroid Build Coastguard Worker goto err_uuid_copy;
1074*344aa361SAndroid Build Coastguard Worker
1075*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
1076*344aa361SAndroid Build Coastguard Worker handle_decref(phandle);
1077*344aa361SAndroid Build Coastguard Worker return (long)new_id;
1078*344aa361SAndroid Build Coastguard Worker
1079*344aa361SAndroid Build Coastguard Worker err_uuid_copy:
1080*344aa361SAndroid Build Coastguard Worker uctx_handle_remove(ctx, new_id, NULL);
1081*344aa361SAndroid Build Coastguard Worker err_install:
1082*344aa361SAndroid Build Coastguard Worker handle_decref(chandle);
1083*344aa361SAndroid Build Coastguard Worker err_accept:
1084*344aa361SAndroid Build Coastguard Worker handle_decref(phandle);
1085*344aa361SAndroid Build Coastguard Worker return (long)ret;
1086*344aa361SAndroid Build Coastguard Worker }
1087*344aa361SAndroid Build Coastguard Worker
1088*344aa361SAndroid Build Coastguard Worker #else /* WITH_TRUSTY_IPC */
1089*344aa361SAndroid Build Coastguard Worker
sys_port_create(user_addr_t path,uint32_t num_recv_bufs,uint32_t recv_buf_size,uint32_t flags)1090*344aa361SAndroid Build Coastguard Worker long __SYSCALL sys_port_create(user_addr_t path,
1091*344aa361SAndroid Build Coastguard Worker uint32_t num_recv_bufs,
1092*344aa361SAndroid Build Coastguard Worker uint32_t recv_buf_size,
1093*344aa361SAndroid Build Coastguard Worker uint32_t flags) {
1094*344aa361SAndroid Build Coastguard Worker return (long)ERR_NOT_SUPPORTED;
1095*344aa361SAndroid Build Coastguard Worker }
1096*344aa361SAndroid Build Coastguard Worker
sys_connect(user_addr_t path,uint32_t flags)1097*344aa361SAndroid Build Coastguard Worker long __SYSCALL sys_connect(user_addr_t path, uint32_t flags) {
1098*344aa361SAndroid Build Coastguard Worker return (long)ERR_NOT_SUPPORTED;
1099*344aa361SAndroid Build Coastguard Worker }
1100*344aa361SAndroid Build Coastguard Worker
sys_accept(uint32_t handle_id,uuid_t * peer_uuid)1101*344aa361SAndroid Build Coastguard Worker long __SYSCALL sys_accept(uint32_t handle_id, uuid_t* peer_uuid) {
1102*344aa361SAndroid Build Coastguard Worker return (long)ERR_NOT_SUPPORTED;
1103*344aa361SAndroid Build Coastguard Worker }
1104*344aa361SAndroid Build Coastguard Worker
1105*344aa361SAndroid Build Coastguard Worker #endif /* WITH_TRUSTY_IPC */
1106