xref: /aosp_15_r20/trusty/kernel/lib/trusty/ipc.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
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